Search code examples
asp.netasp.net-web-apioauth-2.0owin

How to authenticate an access token using OWIN OAuthBearerAuthentication?


What I want:

  1. A token generator use OAuthAuthorizationServer and token consumer use OAuthBearerAuthentication (authenticate the access token).
  2. Use OWIN pipeline to manage all stuff, token stuff and web api stuff.

What about the code:

public void Configuration(IAppBuilder app)
{
    app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
    {
        AuthorizeEndpointPath = "/Authorize",
        AllowInsecureHttp = true,
        Provider = new OAuthAuthorizationServerProvider 
        {
            OnGrantCustomExtension = GrantCustomExtension,
            OnValidateClientRedirectUri = ValidateClientRedirectUri,
            OnValidateClientAuthentication = ValidateClientAuthentication,
        }
    });

    app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
    {
        Provider = new OAuthBearerAuthenticationProvider 
        { 
            //Handles applying the authentication challenge to the response message.
            ApplyChallenge=MyApplyChallenge,

            //Handles processing OAuth bearer token.
            RequestToken=MyRequestToken,

            //Handles validating the identity produced from an OAuth bearer token.
            ValidateIdentity = MyValidateIdentity,
        }
    });

    app.UseWebApi(new WebApplication3.Config.MyWebApiConfiguration());
}

What's the question:

  1. The 3 properties of OAuthBearerAuthenticationProvider, ApplyChallenge, RequestToken and ValidateIdentity. How to implement the 3 methods?

  2. In the token authetication process, What I thought is to decrypt the access token, validate the token from the client, and if the token is validated, put the identities of the token to the HttpContext.Current.User.

    The OAuthBearerAuthenticationProvider's responsibility is to fulfill the previous steps. Am I right?


Solution

  • As you know, UseOAuthAuthorizationServer has the job of authenticating the user. Then, UseOAuthBearerAuthentication has the job of ensuring that only authenticated users can access your application. Often, these two jobs are assigned to different web application. It looks like your application is doing both.

    There are certainly some cases were you need to override the default OAuthBearerAuthenticationProvider. Maybe you do, or maybe you don't In my case, ApplicationCookie didn't quite fit the scenario. So, I'm storing a 3rd party JWT token in a cookie, rather than the header, and using it to indicate that the user is authenticated to a web application. I also needed to redirect to my own login page, rather than provide a 401.

    Here's an implementation that does both:

    public class CustomOAuthBearerProvider : IOAuthBearerAuthenticationProvider
    {
        public Task ApplyChallenge(OAuthChallengeContext context)
        {
            context.Response.Redirect("/Account/Login");
            return Task.FromResult<object>(null);
        }
    
        public Task RequestToken(OAuthRequestTokenContext context)
        {
            string token = context.Request.Cookies[SessionKey];
            if (!string.IsNullOrEmpty(token))
            {
                context.Token = token;
            }
            return Task.FromResult<object>(null);
        }
        public Task ValidateIdentity(OAuthValidateIdentityContext context)
        {
            return Task.FromResult<object>(null);
        }
    }
    

    I didn't need to do anything special in ValidateIdentity, but I needed to satisfy the interface.

    To wire this up, tell your app to use JwtBearerAuthentication with your provider:

    // controllers with an [Authorize] attribute will be validated with JWT
    app.UseJwtBearerAuthentication(
        new JwtBearerAuthenticationOptions
        {
            AllowedAudiences = audiences.ToArray(),
            IssuerSecurityTokenProviders = providers.ToArray(),
            Provider = new CookieOAuthBearerProvider()
        }
    );