Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get IPrincipal from OAuth Bearer Token in OWIN

I have successfully added OAuth to my WebAPI 2 project using OWIN. I receive tokens and can use them in the HTTP Header to access resources.

Now I want to use those tokens also on other channels for authentication that are not the standard HTTP requests that the OWIN template is made for. For example, I am using WebSockets where the client has to send the OAuth Bearer Token to authenticate.

On the server side, I receive the token through the WebSocket. But how can I now put this token into the OWIN pipeline to extract the IPrincipal and ClientIdentifier from it? In the WebApi 2 template, all this is abstracted for me, so there is nothing I have to do to make it work.

So, basically, I have the token as a string and want to use OWIN to access the user information encoded in that token.

Thank you in advance for the help.

like image 555
Sebastian Rösch Avatar asked Dec 14 '13 17:12

Sebastian Rösch


People also ask

How do I get access token from Bearer Token?

The API bearer token's properties include an access_token / refresh_token pair and expiration dates. Tokens can be generated in one of two ways: If Active Directory LDAP or a local administrator account is enabled, then send a 'POST /login HTTP/1.1' API request to retrieve the bearer token.

What Bearer Token contains?

Bearer Tokens are the predominant type of access token used with OAuth 2.0. A Bearer Token is an opaque string, not intended to have any meaning to clients using it. Some servers will issue tokens that are a short string of hexadecimal characters, while others may use structured tokens such as JSON Web Tokens.

Does OAuth use bearer tokens?

OAuth 2.0. The most common way of accessing OAuth 2.0 APIs is using a “Bearer Token”. This is a single string which acts as the authentication of the API request, sent in an HTTP “Authorization” header. The string is meaningless to clients using it, and may be of varying lengths.


2 Answers

I found a part of the solution in this blog post: http://leastprivilege.com/2013/10/31/retrieving-bearer-tokens-from-alternative-locations-in-katanaowin/

So I created my own Provider as follows:

public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider {     public override Task RequestToken(OAuthRequestTokenContext context)     {         var value = context.Request.Query.Get("access_token");          if (!string.IsNullOrEmpty(value))         {             context.Token = value;         }          return Task.FromResult<object>(null);     } } 

Then I needed to add it to my App in Startup.Auth.cs like this:

OAuthBearerOptions = new OAuthBearerAuthenticationOptions() {    Provider = new QueryStringOAuthBearerProvider(),    AccessTokenProvider = new AuthenticationTokenProvider()    {        OnCreate = create,        OnReceive = receive    }, };  app.UseOAuthBearerAuthentication(OAuthBearerOptions); 

With a custom AuthenticationTokenProvider, I can retrieve all other values from the token early in the pipeline:

public static Action<AuthenticationTokenCreateContext> create = new Action<AuthenticationTokenCreateContext>(c => {     c.SetToken(c.SerializeTicket()); });  public static Action<AuthenticationTokenReceiveContext> receive = new Action<AuthenticationTokenReceiveContext>(c => {     c.DeserializeTicket(c.Token);     c.OwinContext.Environment["Properties"] = c.Ticket.Properties; }); 

And now, for example in my WebSocket Hander, I can retrieve ClientId and others like this:

IOwinContext owinContext = context.GetOwinContext(); if (owinContext.Environment.ContainsKey("Properties")) {     AuthenticationProperties properties = owinContext.Environment["Properties"] as AuthenticationProperties;     string clientId = properties.Dictionary["clientId"]; ...  } 
like image 86
Sebastian Rösch Avatar answered Sep 25 '22 22:09

Sebastian Rösch


By default, OWIN use ASP.NET machine key data protection to protect the OAuth access token when hosted on IIS. You can use MachineKey class in System.Web.dll to unprotect the tokens.

public class MachineKeyProtector : IDataProtector {     private readonly string[] _purpose =     {         typeof(OAuthAuthorizationServerMiddleware).Namespace,         "Access_Token",         "v1"     };      public byte[] Protect(byte[] userData)     {        throw new NotImplementedException();     }      public byte[] Unprotect(byte[] protectedData)     {         return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose);     } } 

Then, construct a TicketDataFormat to get the AuthenticationTicket object where you can get the ClaimsIdentity and AuthenticationProperties.

var access_token="your token here"; var secureDataFormat = new TicketDataFormat(new MachineKeyProtector()); AuthenticationTicket ticket = secureDataFormat.Unprotect(access_token); 

To unprotect other OAuth tokens, you just need to change the _purpose content. For detailed information, see OAuthAuthorizationServerMiddleware class here: http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerMiddleware.cs

if (Options.AuthorizationCodeFormat == null) {     IDataProtector dataProtecter = app.CreateDataProtector(         typeof(OAuthAuthorizationServerMiddleware).FullName,         "Authentication_Code", "v1");      Options.AuthorizationCodeFormat = new TicketDataFormat(dataProtecter); } if (Options.AccessTokenFormat == null) {     IDataProtector dataProtecter = app.CreateDataProtector(         typeof(OAuthAuthorizationServerMiddleware).Namespace,         "Access_Token", "v1");     Options.AccessTokenFormat = new TicketDataFormat(dataProtecter); } if (Options.RefreshTokenFormat == null) {     IDataProtector dataProtecter = app.CreateDataProtector(         typeof(OAuthAuthorizationServerMiddleware).Namespace,         "Refresh_Token", "v1");     Options.RefreshTokenFormat = new TicketDataFormat(dataProtecter); } 
like image 33
Johnny Qian Avatar answered Sep 25 '22 22:09

Johnny Qian