Reputation: 121
We wanted to use JSON Web Token (JWT) as API Keys for our new API. They will be used at the server application level, not given to end users to persists in cache. It will allow us to be more granular in authorization than basic auth, without sacrificing the simplicity. Upon researching the idea we found out a service called "Auth0" (https://auth0.com/) is doing exactly this, which seemed to validate our idea.
The thing is that we can't seem to issue JWT indefinitely as .NET "OAuthAuthorizationServerOptions" seems to force us to set an expiration. We've read about "refresh tokens", but after researching for hours and hours its not really clear what would happen to requests made during the refresh.
e.g. If the client asks for a new token and other requests are being made during the time it takes to retrieve the new JWT, then wouldn't those requests fail?
I found some other platforms allow the old token to remain active for an extra minute to accommodate this scenario (e.g. this post: https://laracasts.com/discuss/channels/general-discussion/how-to-refreshing-jwt-token), but again, it seems not available in .NET.
Can anyone explain the proper methods to refresh a token in .NET, but specifically speak to the matter of honoring requests made while retrieving the new token and saving it in the client?
Updating our question with the code...
Token Generation:
private void OAuthTokenGeneration(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(365),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat(ConfigurationManager.AppSettings["as:live"])
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
Authorize...
private void OAuthTokenConsumption(IAppBuilder app)
{
var issuer = ConfigurationManager.AppSettings["as:live"];
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
Upvotes: 0
Views: 5590
Reputation: 1454
The token should be refreshed before it expires, not after. Both the old and new token will be valid until they eventually expire. In this case, requests made using the old token while it's refreshing will work normally.
Here's my recommendation instead of using expiring JWTs + refresh tokens:
OAuthAuthorizationServerOptions
is not related to JWT authentication. I believe you're looking for JwtBearerAuthenticationOptions
instead. This JWT middleware only validates configured parameters such as audiences, signature, etc. but does not issue tokens, so there's no need to configure an expiration time.
Auth0's API uses JWTs for authentication but there is no service that issues these tokens. Instead, tokens are created by any authorized consumer of the API by using a shared API secret, which is used to sign the token. For example, tokens can be generated locally on the browser and with no expiration date using the API Explorer. There is also an endpoint to blacklist tokens by ID (jti
claim) in case they are compromised or are not needed anymore.
Security-wise one could argue that this is practically equivalent to having an expiring JWT + refresh token, since you need a way to blacklist compromised refresh tokens anyway. It's also easier to understand, doesn't use opaque tokens and makes for a less chatty API.
Upvotes: 2