Search code examples
c#asp.netauthenticationjwtowin

Error when trying to use JWT for ASP NET Owin Authentication?


I had the following configuration:

var oAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/api/token"),
            AuthorizeEndpointPath = new PathString("/api/authorize_endpoint"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(int.Parse(ConfigurationManager.AppSettings["AccessTokenTimeSpanInMinutes"])),
            AuthorizationCodeExpireTimeSpan = TimeSpan.FromMinutes(5),
            Provider = new ApiAuthorizationServerProvider(userRepository, externalAppRepository),
            RefreshTokenProvider = new ApiRefreshTokenProvider(),
            AuthorizationCodeProvider = new ApiExternalAuthenticationTokenProvider(externalAppRepository)
        };

        // Token Generation
        app.UseOAuthAuthorizationServer(oAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

I read somewhere that they added a JwtFormat object I could use in the options, by setting AccessTokenFormat, but when I did that and my options looked something like this:

var oAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/api/token"),
            AccessTokenFormat = new JwtFormat(new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("secretkey")),
                ValidateLifetime = false,
                ValidateIssuer = false,
                ValidateAudience = false
            }),
            AuthorizeEndpointPath = new PathString("/api/authorize_endpoint"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(int.Parse(ConfigurationManager.AppSettings["AccessTokenTimeSpanInMinutes"])),
            AuthorizationCodeExpireTimeSpan = TimeSpan.FromMinutes(5),
            Provider = new ApiAuthorizationServerProvider(userRepository, externalAppRepository),
            RefreshTokenProvider = new ApiRefreshTokenProvider(),
            AuthorizationCodeProvider = new ApiExternalAuthenticationTokenProvider(externalAppRepository)
        };

        // Token Generation
        app.UseOAuthAuthorizationServer(oAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

My OnGrantResourceOwnerCredentials method throws an exception of MethodNotSupported

StackTrace:

[NotSupportedException: Specified method is not supported.]
   Microsoft.Owin.Security.Jwt.JwtFormat.Protect(AuthenticationTicket data) +40
   Microsoft.Owin.Security.OAuth.<InvokeTokenEndpointAsync>d__8.MoveNext() +4143
   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +32
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62
   Microsoft.Owin.Security.OAuth.<InvokeAsync>d__5.MoveNext() +1098
   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +32
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62
   Microsoft.Owin.Security.Infrastructure.<Invoke>d__5.MoveNext() +517
   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +32
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<RunApp>d__5.MoveNext() +197
   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +32
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<DoFinalWork>d__2.MoveNext() +184
   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +32
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +118
   System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +510
   System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +220
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +134

From what I've gathered, that exception is

Thrown if the IssuingSecurityTokenProvider is not a SigningSecurityTokenProvider.

Could anyone shine some light on this?


Solution

  • To generate JWT token, the library needs to execute the Protect() method. However Microsoft hasn't provided an implementation for the Protect() method (The error message gives a hint "Specified method is not supported" ). It only provides an implementation of Unprotect() method. You can verify this by peeking into the library using ILDASM.

    So we cannot directly use AccessTokenFormat = new JwtFormat() to generate a JWT token. That being said, to generate a JWT token, you need to write a custom class which implements ISecureDataFormat interface. This interface provides two methods Protect() and Unprotect(). To generate JWT token, you only need to implement Protect() method and use this class as access token format.

    The below link gives a very good explanation of how to implement this class and it's usage.

    https://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/