How to share an Access Token between an MVC 5 web application and Web API 2 application
Asked Answered
S

2

9

In this instance I am having the user log into the (MVC 5) Web application, which then acts as proxy to log into the (Web API 2) API (using basic over SSL) and return a Bearer/Access Token. I'm using the Thinktecture.IdentityModel.Client.OAuth2Client to handle the login and get the access token, which all works fine.

Some other stuff happens but now I want the Web application to be able to decode the Access Token to access the claims set on the API (specifically the user ID returned after login to the API).

I'm using the much demoed, UseOAuthAuthorizationServer and UseOAuthBearerAuthentication extension methods with a token endpoint pretty much out of the box but with a custom OAuthAuthorizationServerOptions.Provider to access my own repository.

I have the same MachineKey on both applications, but I am unclear how to decode the token , although I understand I would probably have to use the SecureDataFormat.Unprotect method.

The closest attempt I have in the Web application is:

Task<TokenResponse> response = client.RequestResourceOwnerPasswordAsync(model.Email, model.Password);

IDataProtector dataProtecter = Startup.DataProtectionProvider.Create("does this matter?");
TicketDataFormat ticketDataFormat = new TicketDataFormat(dataProtecter);
AuthenticationTicket ticket = ticketDataFormat.Unprotect(response.Result.AccessToken);

With the Startup.DataProtectionProvider set as follows:

public partial class Startup
{
    internal static IDataProtectionProvider DataProtectionProvider { get; private set; }

    public void Configuration(IAppBuilder app)
    {
        DataProtectionProvider = app.GetDataProtectionProvider();
        this.ConfigureAuth(app);
    }
}

My fall back plan is to offer an API method that returns the information I am interested in after login, but it seems excessive seeing as it forms part of the claims in the token (as I understand it).

I have tried to wrap my head around JWT (I've looked at Thinktecture, Microsoft source code and various other forums), but not sure if that would help (although claims being available in plain text us useful). I have yet to find an example that allows sign in with basic authentication and returns a custom JWT containing an access token.

Anyway I hope thats enoguh information and any help would be much appreciated... cheers

Syndetic answered 19/8, 2014 at 18:54 Comment(0)
M
4

You guys got very close. Shadi was on the right track. Even if this is a separate mvc application, you still need to decrypt the token as shown and extract the claim. If your web api token is in the variable called accessToken, you can do the following in your mvc web app. (Note that mvc is using both bearer authentication and cookie authentication and OAuthBearerOptions is a static class)

//Unprotect the token 
var unencryptedToken = Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(accessToken);
//Extract the claims identity from the token
var identity = unencryptedToken.Identity;

//Once you have the claims identity extracted, create a new claims identity that uses 
//ApplicationCookie as the default authentication type

var id = new ClaimsIdentity(identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);

// Now you are ready to sign in with your new claims identity. You basically created an  
//application cookie from a bearer token and now using this cookie to sign-in

AuthenticationManager.SignIn(id);

Here is how your startup.auth.cs should include (note that we have an OAuthBearerAuthenticationOptions static member and we call app.UseOAuthBearerAuthentication() just to be able to decrypt the bearer token

public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }

    static Startup()
    {
        OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
    }


    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseOAuthBearerAuthentication(OAuthBearerOptions);
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });
    }
Malcolmmalcom answered 29/12, 2014 at 22:11 Comment(0)
J
1

If you are using the UseOAuthBearerAuthentication you can make the OAuthBearerOptions as static on the Startup.Auth.cs class:

public partial class Startup
{
    public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
    ...

    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and signin manager to use a single instance per    request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
        app.UseOAuthBearerAuthentication(OAuthBearerOptions);
        ...

    }
}

Now from anywhere in the code you can unprotect the received token this way:

var ticket = Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(response.Result.AccessToken);

Now you can use the ticket for your access the claims for the API user:

ticket.Identity.Claims

Hope this would answer your question.

EDIT

This answer on SO would solve your problem please have a look.

Judaism answered 26/10, 2014 at 13:34 Comment(5)
Hi Shadi, thansk for the response, yes I have set up my security using that method already. What I am actually trying to do is decrypt the token from a completely separate MVC application.Syndetic
What kind of application you are trying to decrypt the token at? is it class library, service, Web Api, Java?Judaism
Hi Shadi as per the description above an (MVC 5) Web applicationSyndetic
I forgot to say that I updated my answer and I pointed to another SO questionJudaism
Hi Shadi, I'm afraid that question relates to a different problem. In fact I have seen it before and I also posted a response against it.Syndetic

© 2022 - 2024 — McMap. All rights reserved.