How to implement the OAuth2 Auth_Code flow?

Viewed 533

Purpose: I work with a third party that has implemented an OAuth2 authorization code flow. The goal is for an authenticated user in my app to be able to access areas of a this third parties app without having to sign in to the third party. I have provided the third party with our authorization url, a clientId and a callback url (not sure how this is used).

I am trying to wire up a basic authorization code flow using OAuth2, but I am stuck on an invalid_grant error and am having trouble determining how the process is intended to work.

Here is what I have implemented thus far:

In the startup class I configure my OAuth server to include an AuthorizeEndpointPath and an AuthorizationCodeProvider:

var allowInsecureHttp = bool.Parse(ConfigurationManager.AppSettings["AllowInsecureHttp"]);

var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
    AllowInsecureHttp = allowInsecureHttp,
    TokenEndpointPath = new PathString("/oauth2/token"),
    AuthorizeEndpointPath = new PathString("/oauth2/authorize"),
    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
    Provider = new CustomOAuthProvider(HlGlobals.Kernel),
    AccessTokenFormat = new CustomJwtFormat(_baseUrl, HlGlobals.Kernel),
    AuthorizationCodeProvider = new SimpleAuthenticationTokenProvider()
};

The CustomOAuthProider contains the following overrides:

public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
    //We validated that Client Id and redirect Uri are what we expect
    if (context.ClientId == "123456" && context.RedirectUri.Contains("localhost"))
    {
        context.Validated();
    }
    else
    {
        context.Rejected();
    } 

    return Task.FromResult<object>(null);
}

public override Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
{
    var ci = new ClaimsIdentity("Bearer");
    context.OwinContext.Authentication.SignIn(ci);
    context.RequestCompleted();

    return Task.FromResult<object>(null);
}

public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
    string clientId;
    string clientSecret;
    Guid clientIdGuid;    

    // Validate the context
    context.Validated();
    return Task.FromResult<object>(0);
}

Finally, the code in the SimpleAuthenticationTokenProvider is implemented as follows:

public SimpleAuthenticationTokenProvider() : base()
{
    this.OnCreate = CreateCode;
    this.OnReceive = ReceiveCode;
}

private readonly ConcurrentDictionary<string, string> _authenticationCodes = new ConcurrentDictionary<string, string>(StringComparer.Ordinal);

public void CreateCode(AuthenticationTokenCreateContext context)
{
    context.SetToken(Guid.NewGuid().ToString("n") + Guid.NewGuid().ToString("n"));
    _authenticationCodes[context.Token] = context.SerializeTicket();
}


public void ReceiveCode(AuthenticationTokenReceiveContext context)
{
    string value;
    _authenticationCodes.TryGetValue(context.Token, out value);
    context.DeserializeTicket(value);
}

I have wired up a sample request inside of Postman. When I execute the postman oauth2 Authroization Code grant type the following methods from above fire sequentially:

  1. ValidateClientRedirectUri
  2. AuthorizeEndpoint
  3. ValidateClientAuthentication
  4. ReceiveCode

I am getting back an 'invalid_grant' error from postman, and no authorization code has been returned.

Can anyone point out where I may be going wrong here?

Secondly, how is the callbackurl/redirect url supposed to be used? Is it a fallback to the login page if the user has not authenticated?

UPDATE I see that a 'code' is coming back in the querystring attached to the redirectURL on the response. Should the redirectURL be a page on the third-party site?

How is this code exchanged for a token?

UPDATE 2 Another question: At what phase do I read/parse the code? I can see the code coming in on the request querystring in my GrantClientCredentials method. Should I just parse it from the querystring and validate? At what point should ReceiveCode be called?

0 Answers
Related