Registering Web API 2 external logins from multiple API clients with OWIN Identity

Update: things have changed since I wrote this post in January: MSFT released their official OpenID connect client middleware and I worked hard with @manfredsteyer to adapt the OAuth2 authorization server built in Katana to OpenID connect. This combination results in a far easier and far more powerful solution that doesn’t require any custom client code and is 100% compatible with standard OAuth2/OpenID connect clients. The different steps I mentioned in January can now be replaced by just a few lines:

Server:

app.UseOpenIdConnectServer(options =>
{
    options.TokenEndpointPath = new PathString("/connect/token");
    options.SigningCredentials.AddCertificate(certificate);

    options.Provider = new CustomOpenIdConnectServerProvider();
});

Client:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
    Authority = "http://localhost:55985/",

    ClientId = "myClient",
    ClientSecret = "secret_secret_secret",
    RedirectUri = "http://localhost:56854/oidc"
});

You can find all the details (and different samples) on the GitHub repository:

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Nancy


Josh, you’re definitely on the right track and your delegated/federated authentication implementation seems pretty good (I imagine that you’ve used the predefined OWIN middleware from Microsoft.Owin.Security.Facebook/Google/Twitter).

What you need to do is creating your own custom OAuth2 authorization server. You have plenty of options to achieve that, but the easiest one is probably to plug the OAuthAuthorizationServerMiddleware in your OWIN Startup class. You’ll find it in the Microsoft.Owin.Security.OAuth Nuget package.

While the best practice would be to create a separate project (often called “AuthorizationServer”), I personally prefer adding it to my “API project” when it is not meant to be used across multiple API (here, you would have to insert it in the project hosting “api.prettypictures.com”).

You’ll find a great sample in the Katana repository:

https://katanaproject.codeplex.com/SourceControl/latest#tests/Katana.Sandbox.WebServer/Startup.cs

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    AuthorizeEndpointPath = new PathString("/oauth2/authorize"),
    TokenEndpointPath = new PathString("/oauth2/token"),
    ApplicationCanDisplayErrors = true,

    AllowInsecureHttp = true,

    Provider = new OAuthAuthorizationServerProvider
    {
        OnValidateClientRedirectUri = ValidateClientRedirectUri,
        OnValidateClientAuthentication = ValidateClientAuthentication,
        OnGrantResourceOwnerCredentials = GrantResourceOwnerCredentials,
    },
    AuthorizationCodeProvider = new AuthenticationTokenProvider
    {
        OnCreate = CreateAuthenticationCode,
        OnReceive = ReceiveAuthenticationCode,
    },
    RefreshTokenProvider = new AuthenticationTokenProvider
    {
        OnCreate = CreateRefreshToken,
        OnReceive = ReceiveRefreshToken,
    }
});

Don’t hesitate to browse the whole project to see how the authorization consent form has been implemented using simple Razor files. If you prefer a higher-level framework like ASP.NET MVC or NancyFX, create your own AuthorizationController controller and Authorize methods (make sure to accept both GET and POST) and use Attribute Routing to match the AuthorizeEndpointPath defined in your OAuth2 authorization server (ie. [Route("oauth2/authorize")] in my sample, where I’ve changed the AuthorizeEndpointPath to use oauth2/ as a path base).

The other thing you need to do is adding an OAuth2 authorization client in your web app. Unfortunately, there’s no generic OAuth2 client support in Katana, and you’ll have to build your own. I’ve personally submitted a proposal to the Katana team, but it has been refused. But don’t panic, it’s rather easy to do:

Copy the appropriate files from the Microsoft.Owin.Security.Google repository located there: https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs

You’ll need GoogleOAuth2AuthenticationHandler, GoogleOAuth2AuthenticationMiddleware, GoogleOAuth2AuthenticationOptions, GoogleAuthenticationExtensions (you’ll have to remove the first 2 methods corresponding to the Google OpenID implementation), IGoogleOAuth2AuthenticationProvider, GoogleOAuth2ReturnEndpointContext, GoogleOAuth2AuthenticationProvider, GoogleOAuth2AuthenticatedContext and GoogleOAuth2ApplyRedirectContext. Once you’ve inserted these files in your project hosting “webpics.com”, rename them accordingly and change the authorization and access token endpoints URL in GoogleOAuth2AuthenticationHandler to match the ones you’ve defined in your OAuth2 authorization server.

Then, add the Use method from your renamed/custom GoogleAuthenticationExtensions to your OWIN Startup class. I suggest using AuthenticationMode.Active so that your users will be directly redirected to your API OAuth2 authorization endpoint. Thus, you should suppress the “api.prettypictures.com/Account/ExternalLogins” roundtrip and let the OAuth2 client middleware alter 401 responses to redirect the clients to your API.

Good luck. And don’t hesitate if you need more information 😉

Leave a Comment