I have a self-hosted OWIN application configured as an authorization server and a signalr resource server.
My clients are successfully obtaining the bearer token and presenting it for authorization in subsequent calls to the signalR hub.
My next step is to decouple the authorization service so that it can run on its own host. To get started I created a separate self-hosted app that contains only the authorization service code. It's still all in one solution on my development machine, but the authorization service and signalR resources are hosted in separate processes.
The auth flow is still working properly. The token is getting to my resource server, but now getting 401 unauthorized from the signalR hub.
There is alot of support out there for solving this in ASP.Net Web API, in which you would sync up a machine.config value in your web.config files. But that is not my architecture. Running as a self-hosted app under HttpListener uses different encryption, DPAPI by default.
There doesn't seem to be much discussion out there about solving this in a self-hosted architecture. My theory is that even under different processes on the same machine, the DPAPI decryption is failing and so I get 401.
I'm trying to figure out if there is some minimal approach to solving this or if I have to completely refactor maybe to use JWT instead.
EDIT: adding some code to help display my setup
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = false,
TokenEndpointPath = new PathString("/account/login"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
public void ConfigureOAuth(IAppBuilder app)
{
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
Provider = new ApplicationOAuthBearerAuthenticationProvider(),
});
}
Posting my own solution hopefully to help someone else down the road.
I did decide to implement a JWT solution rather than use the default. I think this is the better architecture anyway, decoupling your token encryption from the OS. I used this tutorial http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/
The crucial bits were creating your custom OAuthAuthorizationServerProvider and ISecureDataFormat for encrypting the token as shown in the tutorial. This just shows the OWIN config.
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = false,
TokenEndpointPath = new PathString("/account/login"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new JwtAuthorizationServerProvider(),
AccessTokenFormat = new CustomJwtFormat("https://foo.test.com")
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
Another issue you might face is getting the token to SignalR, where setting the Authorization header is not as straight forward as you might think. As it happens the cookie based implementation in this tutorial worked beautifully with JWT as well! http://blog.marcinbudny.com/2014/05/authentication-with-signalr-and-oauth.html#.VmWgMXarSCd
Again here is the OWIN config example.
public void ConfigureOAuth(IAppBuilder app)
{
//app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
//{
// Provider = new ApplicationOAuthBearerAuthenticationProvider()
//});
var issuer = "https://foo.test.com";
var audience = "client_id";
var secret = TextEncodings.Base64Url.Decode("ABCDEF");
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audience },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
},
Provider = new ApplicationOAuthBearerAuthenticationProvider()
});
}