4
votes

Is there a way to read/decrypt a bearer token in the web api project?

My web api is also hosting SignalR hubs which are called from the browser via websocket. Unlike my normal api calls I cannot add the authorization header here. Though I can send the token in the query string and read this in the SignalR hub.

By default the token is resolved by owin into a claims identity. What I need is to do this manually. How would I do that?

    OAuthAuthorizationServerOptions serverOptions = new OAuthAuthorizationServerOptions()
    {
        AllowInsecureHttp = true,
        TokenEndpointPath = new PathString("/token"),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(Config.TokenLifetime),
        Provider = new AuthProvider()
    };

    // Token Generation
    app.UseStageMarker(PipelineStage.Authenticate); // wait for authenticate stage, so we get the windows principle for use with ntlm authentication
    app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    app.UseOAuthAuthorizationServer(serverOptions);
1
are you using OAuthBearerAuthenticationOptions to generate tokens?Nikola.Lukovic
One way is to store the authentication provider in a static variable in the owin startup class and call it when you need to get the claims from a token.Marcus Höglund
@Nikola.Lukovic: yesVince Black
I have just added my configuration to the postVince Black
@VinceBlack Check Nikolas answer:)Marcus Höglund

1 Answers

3
votes

I assume that in Startup.cs you have a code similar to this:

var oAuthOpt = new OAuthBearerAuthenticationOptions
{
    Provider = new OAuthTokenProvider(
        req => req.Query.Get("bearer_token"),
        req => req.Query.Get("access_token"),
        req => req.Query.Get("refresh_token"),
        req => req.Query.Get("token"),
        req => req.Headers.Get("X-Token"))
};

app.UseOAuthBearerAuthentication(OAuthOpt);

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    AllowInsecureHttp = true,
    TokenEndpointPath = new PathString(settings.TokenEndpointBasePath),
    AccessTokenExpireTimeSpan = Util.AccessTokenExpireTimeSpan,
    Provider = new AuthorizationServerProvider(new AuthenticationService()),
});

What you have to do is to replace oAuthOpt with a public static field in Startup.cs and than use it when you need to unprotect your bearer tokens.

For SignalR i'm creating an Authorization attribute where i take that oAuthOpt and use it decode tokens.

This is how I do it:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class AuthorizeHubAttribute : AuthorizeAttribute
{
    public override bool AuthorizeHubConnection (HubDescriptor hubDescriptor, IRequest request)
    {
        var token = request.QueryString["Authorization"];
        var ticket = Startup.OAuthOpt.AccessTokenFormat.Unprotect(token);
        if ( ticket != null && ticket.Identity != null && ticket.Identity.IsAuthenticated )
        {
            request.Environment["server.User"] = new ClaimsPrincipal(ticket.Identity);
            return true;
        }
        else
            return false;
    }

    public override bool AuthorizeHubMethodInvocation (IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod)
    {
        var connectionId = hubIncomingInvokerContext.Hub.Context.ConnectionId;
        var environment = hubIncomingInvokerContext.Hub.Context.Request.Environment;
        var principal = environment["server.User"] as ClaimsPrincipal;
        if ( principal != null && principal.Identity != null && principal.Identity.IsAuthenticated )
        {
            hubIncomingInvokerContext.Hub.Context = new HubCallerContext(new Microsoft.AspNet.SignalR.Owin.ServerRequest(environment), connectionId);
            return true;
        }
        else
            return false;
    }
}

var ticket = Startup.OAuthOpt.AccessTokenFormat.Unprotect(token);

That line is the connection with Startup.cs