OpenID Connect Hybrid Flow and IdentityServer v3

One of the features we added in Beta 2 is support for hybrid flow (see spec).  What is hybrid flow – and why do I care?

Well – in a nutshell – OpenID Connect originally extended the two basic OAuth2 flows (or grants) called authorization code and implicit. Implicit allows requesting tokens without explicit client authentication (hence the name), but uses the redirect URI instead to verify client identity. Because of that, requesting long lived tokens like a refresh token is not allowed in that flow.

Authorization code flow on the other hand only returns a so called authorization code via the unauthenticated front channel, and requires client authentication using client id and secret (or some other mechanism) to retrieve the actual tokens (including a refresh token) via the back channel. This mechanism was originally designed for server-based applications only, since storing client secrets on a client device is questionable without the right security mechanisms in place.

Hybrid flow (as the name indicates) is a combination of the above two. It allows to request a combination of identity token, access token and code via the front channel using either a fragment encoded redirect (native and JS based clients) or a form post (server-based web applications). This enables e.g. scenarios where your client app can make immediate use of an identity token to get access to the user’s identity but also retrieve an authorization code that that can be used (e.g. by a back end service) to request a refresh token and thus gaining long lived access to resources.

Lastly, hybrid flow is the only flow supported by the Microsoft OpenID Connect authentication middleware (in combination with a form post response mode), and before we added support for hybrid flow to IdentityServer, interop was a bit complicated (see here).

Our samples repo has two clients using hybrid flow – native and web. Let’s have a look at the middleware based one.

You are using hybrid flow whenever you have a response type of code combined with some other response type, e.g. id_token or token (or both).

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions

    {

        ClientId = “katanaclient”,

        Authority = Constants.BaseAddress,

        RedirectUri = Constants.RedirectUri,

        PostLogoutRedirectUri = Constants.PostLogoutUri,

        ResponseType = “code id_token token”,

        Scope = “openid email profile read write offline_access”,

 

        SignInAsAuthenticationType = “Cookies”

    };

 

The scopes are a combination of identity scopes allowing us to retrieve user identity (email and profile), resource scopes for api access (read and write) and a request for a refresh token (offline_access).

After authentication (and consent), the middleware will validate the response and notify you when it has retrieved the authorization code from the callback form post. You then typically have a number of responsibilities, e.g.

  • Contact the userinfo endpoint to retrieve the claims about the user
  • Transform the claims to whatever format your application expects
  • Store the access token for later use (along with information about its lifetime)
  • Store the refresh token so you can refresh expired access tokens (if long lived access is needed)
  • Store the id_token if you need features at the OpenID Connect provider that requires id token hints (e.g. redirects after logging out)

In our sample, I first strip all the protocol related claims from the identity token:

// filter "protocol" claims
var claims = new List<Claim>(from c in n.AuthenticationTicket.Identity.Claims
                                where c.Type != "iss" &&
                                      c.Type != "aud" &&
                                      c.Type != "nbf" &&
                                      c.Type != "exp" &&
                                      c.Type != "iat" &&
                                      c.Type != "nonce" &&
                                      c.Type != "c_hash" &&
                                      c.Type != "at_hash"
                                select c);

 

…then get the user claims from the user info endpoint

// get userinfo data
var userInfoClient = new UserInfoClient(
    new Uri(Constants.UserInfoEndpoint),
    n.ProtocolMessage.AccessToken);
 
var userInfo = await userInfoClient.GetAsync();
userInfo.Claims.ToList().ForEach(ui => claims.Add(new Claim(ui.Item1, ui.Item2)));

 

…and retrieve a refresh token (and a fresh access token)

// get access and refresh token
var tokenClient = new OAuth2Client(
    new Uri(Constants.TokenEndpoint),
    "katanaclient",
    "secret");
 
var response = await tokenClient.RequestAuthorizationCodeAsync(
    n.Code, n.RedirectUri);

 

Then I combine all the claims together and store them in the authentication cookie:

claims.Add(new Claim("access_token", response.AccessToken));
claims.Add(new Claim("expires_at", 
    DateTime.Now.AddSeconds(response.ExpiresIn).ToLocalTime().ToString()));
claims.Add(new Claim("refresh_token", response.RefreshToken));
claims.Add(new Claim("id_token", n.ProtocolMessage.IdToken));
 
n.AuthenticationTicket = new AuthenticationTicket(
    new ClaimsIdentity(claims.Distinct(new ClaimComparer()), 
        n.AuthenticationTicket.Identity.AuthenticationType), 
        n.AuthenticationTicket.Properties);

 

You might not need all of the above steps, but this is how it generally works. HTH.

Posted in IdentityServer, Katana, OAuth, OpenID Connect, OWIN, WebAPI | Leave a comment

Identity & Access Control at NDC London 2014

The NDC Agenda is out now – and Brock and me will do a number of identity & access control related sessions.

Brock will talk about identity management in ASP.NET – which is a huge topic – so he split up his talk into two sessions. I will cover OpenID Connect and OAuth2 – and especially the combination of the two protocols. Looking forward to that!

In addition we will do a 2-day workshop on monday/tuesday titled: “Identity & Access Control for modern Web Applications & APIs” – this will be deep dive in all the things you need to know to implement authentication and authorization into modern distributed applications. See the agenda here.

Early bird ends on 15th October – would be cool to meet you there and talk about security!

Posted in .NET Security, ASP.NET, IdentityModel, IdentityServer, Katana, OAuth, OpenID Connect, OWIN, WebAPI | 6 Comments

IdentityServer v3 – Beta 2

We just pushed IdentityServer v3 beta 2 to github and nuget.

This time it’s been 161 commits and we added a lot of small things – and a couple of bigger things, e.g.:

  • Update to Katana v3 and JWT handler v4
  • Configurable claims for both identity and resource scopes
  • Added support for acr_values and tenant login hints
  • Improved support for custom grant types
  • Added a RequireSsl switch (thus removing the need for the public host name setting)
  • Reworked some internals like the user service, token service, userinfo endpoint, sign in message and validation pipeline
  • Added support for hybrid flow and thus improved compatibility with the Microsoft Katana OpenID Connect middleware
  • Added identity token validation endpoint for clients that don’t have access to the necessary crypto libraries
  • More control over CSP and cookies

Docs will be updated in the next days.

As always – thank you very much for feedback, bug reports etc… we are getting closer to RTW!

Posted in ASP.NET, IdentityServer, Katana, OAuth, OpenID Connect, OWIN, WebAPI | 5 Comments

401 vs 403

For years, there’s been an ongoing discussion which HTTP status code to use for “not authorized” scenario – and the original HTTP 1.1 specification wasn’t exactly crystal clear about the distinction between 401 (unauthorized) and 403 (forbidden).

But there is definitely the need to distinguish between the situation where no or invalid credentials were supplied with a request and the situation where a valid credential was supplied, but the “entity” belonging to that credential is not authorized for the operation it is trying to do.

Here are some examples:

  • In good old ASP.NET FormsAuth (well this also applies to the brand new cookie middleware in Katana) – a 401 is turned into a 302 to the login page. That’s fine for anonymous requests – but when a user is already authenticated, a failed authorization (e.g. using [Authorize(Role=”foo”)]) will result in showing the login page again – not very intuitive. You rather want do deal with that error or or show an error page.
  • In Web APIs and token based authentication your client need to be able to distinguish if the token is e.g. expired or if it is missing the necessary scopes. The “Bearer Token Usage” spec (http://tools.ietf.org/html/rfc6750) is pretty clear about this. Expired or malformed tokens should return a 401 – missing scopes should result in a 403.

You might have heard that the HTTP 1.1 spec has been re-written recently. It is now clearer on the status codes as well (you know it is getting serious when you see a Courier font, right?):

The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource. The server generating a 401 response MUST send a WWW-Authenticate header field (Section 4.1) containing at least one challenge applicable to the target resource.

A server that receives valid credentials that are not adequate to gain access ought to respond with the 403 (Forbidden) status code.

Unfortunately, the ASP.NET MVC/Web API [Authorize] attribute doesn’t behave that way – it always emits 401. The logic would be simple for failed authorization: “if user is anonymous – emit 401, if not – emit 403” (we now emit 403s for our scope authorization helpers – here and here).

Maybe we can fix that in vNext.

Posted in .NET Security, ASP.NET, Katana, OAuth, OWIN, WebAPI | Leave a comment

IdentityServer Beta 1-2

Yesterday we pushed another interim release of IdentityServer to nuget.  You can see all commits here if you are interested.

Besides many smaller changes and bug fixes – the main new feature is that you can now configure which claims go into identity and access tokens. This allows sending e.g. a ‘role’ claim to a resource.

Before that change, this always required extending the claims provider. Check the wiki for updated docs.

Internally, everything is based now on Katana and the JWT handler v4 – which allowed to finally fix the data types of claims like ‘iat’ or ‘auth_time’ to numbers (before that the JWT handler only allowed strings). This improvers interop with other OIDC systems. Katana v3 is also a pre-req for supporting WS-Federation and OIDC based upstream IdPs, which is a feature that we will soon start working on.

We also moved all active development to the dev branch and periodically publish dev nugets to myget. See here.

As always, and feedback is appreciated. Thanks for the support so far!

Posted in .NET Security, ASP.NET, IdentityServer, Katana, OAuth, OpenID Connect, OWIN, WebAPI | Leave a comment

Announcing Thinktecture IdentityServer v3 – Beta 1

It’s done – and I am happy (and a bit exhausted) – a few minutes ago I closed the last open issue for Beta 1.

What’s new
It’s been 424 commits since we released Preview 1 – so there is quite a lot of new stuff, but the big features are:

  • A completely revamped configuration system that allows replacing bits and pieces of the core server itself – including a DI system
  • A plugin infrastructure that allows adding new endpoints (WS-Federation support is a plugin e.g.)
  • Refresh tokens
  • Infrastructure that allows customizing views and UI assets for re-branding as well as extensibility to insert your own workflows like registration or EULAs
  • Support for CORS and HTTP strict transport security
  • Content Security Policy (CSP) & stricter caching rules
  • Protection against click-jacking
  • Control over cookies (lifetime, naming etc)
  • more extensibility points

Repositories
We also split up the solution into separate repos and nugets for better composability:

Samples and documentation
We also have a separate repo for samples and added quite a bit of content to the wiki.

With that I am now leaving for holidays! ;) Give IdentityServer a try and give us feedback. A big thanks to all contributors and the people that engaged with us over the various channels!!!

Have a nice summer!

Posted in .NET Security, ASP.NET, IdentityServer, Katana, OAuth, OpenID Connect, OWIN, Uncategorized, WebAPI | 10 Comments

NDC London: Identity and Access Control for modern Web Applications and APIs

I am happy to announce that NDC will host our new workshop in London in December!

Join us to learn everything that is important to secure modern web applications and APIs using Microsoft’s current and future web stack! Looking forward to it!

course description / ndc london / tickets

Posted in .NET Security, ASP.NET, IdentityModel, IdentityServer, Katana, OAuth, OpenID Connect, OWIN, WebAPI | 1 Comment