Which OpenID Connect/OAuth 2.0 Flow is the right One?

That is probably the most common question we get – and the answer is of course: it depends!

Machine to Machine Communication
This one is easy – since there is no human directly involved, client credentials are used to request tokens.

Browser-based Applications
This might be a JavaScript-based application or a “traditional” server-rendered web application. For those scenarios, you typically want to use the implicit flow (OpenID Connect / OAuth 2.0).

A side effect of the implicit flow is, that all tokens (identity and access tokens) are delivered through the browser front-channel. If you want to use the access token purely on the server side, this would result in an unnecessary exposure of the token to the client. In that case I would prefer the authorization code flow – or hybrid flow.

Native Applications
Strictly speaking, a native application has very similar security properties compared to a JavaScript application. Still they are generally considered a bit more easy to secure because you often have stronger platform support for protecting data and isolation.

That’s the reason why the current consensus is, that an authorization code based flow gives you “a bit more” security than implicit. The much more important reason IMO is, that there are a couple of (upcoming) protocols that are optimized for native clients, and they use code exchange and the token endpoint as a foundation – e.g. PKCE, Proof of Possession and AC/DC.

Remark 1: With native applications I mean applications that have access to platform-native APIs like data protection or maybe the system browser. Cordova applications are e.g. written in JavaScript, but I would not consider them to be a “browser-based application”.

Remark 2: For code based flows, you need to embed the client secret in the client application. Of course you can’t treat that as a secret anymore – no matter how good you protect it, a motivated attacker will be able to reverse engineer it. It is still a bit better than no secret at all. Specs like PKCE make it a bit better as well.

Remark 3: I often hear the argument that the client application does not care who the user is, it just needs an access token – thus we rather do OAuth 2.0 than OpenID Connect. While this might be strictly speaking true – OIDC is the superior protocol as it includes a couple of extra security features like nonces for replay protection or c_hash and at_hash to link the (verifiable) identity token to the (unverifiable) access token.

Remark 4: As an extension to remark 3 – always use OpenID Connect – and not OAuth 2.0 on its own. There should be client libraries for every platform of interest by now. ASP.NET has middleware, we have a library for JavaScript. Other platforms should be fine as as well.

Remark 5: Whenever you think about using authorization code flow – rather use hybrid flow. This gives you a verifiable token first before you make additional roundtrips (another extensions of remark 3 and 4).

HTH

This entry was posted in .NET Security, IdentityServer, OAuth, OpenID Connect, WebAPI. Bookmark the permalink.

55 Responses to Which OpenID Connect/OAuth 2.0 Flow is the right One?

  1. Pieter De Rycke says:
  2. Alex White says:

    Do you have any views on the pros and cons of using server side proxies for javascript use, as Alex Bilbie blogged about here: http://alexbilbie.com/2014/11/oauth-and-javascript/

  3. Regimantas says:

    Hey,

    Thanks for comparison, it was really helpful. I want to clear some things to myself.
    As I understand authorization code flow is the most secure one, because client secret is stored in client server ? Are there any other significant security differences between auth code/hybrid flows?
    Trying to come up with design for [native client -> idSrv -> native client (for authentication)] and got lost a bit in those flows.

  4. According to the OIDC specs you are allowed to call the Authorization Endpoint in the Hybrid flow with a response type of code id_token token in which case both the ID Token as well as the Access Token is returned from the Authorization Endpoint, Why would you use this over just using Implicit flow then?

    • code id_token returns an identity token and a code. not an access token.

      • robbaman says:

        Yeah, I said a response type of “code id_token token” but I can see how that’s easily overlooked :)

      • ah ok ;)

        well – that gives you an access token immediately – in addition to getting a code. Maybe you want to use that access token to secure the first hop to deliver the code to some backend.

        I personally never used that combination.

  5. Lukas says:

    Is the following correct: Because we use the Client Credential Flow for Client to API calls without user interaction:
    – for the first call, the client must always: 1) first ask Identity Server for a token, 2) then go to the API. (make two calls)
    – For the client credentials flow, only scopes with type “resource” are allowed.

  6. Hi, thanks for the effort…
    How can I use a hybrid flow’s AccessToken and UserInfo to secure WebSockets communicating a Web Socket Server, Is it possible to pass the token to Socket Server (another IS3 client) to validate it via IS3 like a SSO scenario.
    Thanks
    Regards

  7. Hi, interesting article, thanks.

    With regards to your Remark 5, “Whenever you think about using authorization code flow – rather use hybrid flow. This gives you a verifiable token first before you make additional roundtrips (another extensions of remark 3 and 4).”:

    How do you reconcile your statement with the guidance that “ID Tokens MUST NOT be encoded in the query string.”? (from http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Security) below.

    Should they also use response mode form post? (and is that really achievable with mobile apps?)

    7. Security Considerations
    There are security implications to encoding response values in the query string. The HTTP Referer header includes query parameters, and so any values encoded in query parameters will leak to third parties. Thus, while it is safe to encode an Authorization Code as a query parameter when using a Confidential Client (because it can’t be used without the Client Secret, which third parties won’t have), more sensitive information such as Access Tokens and ID Tokens MUST NOT be encoded in the query string. In no case should a set of Authorization Response parameters whose default Response Mode is the fragment encoding be encoded using the query encoding.

    thanks!

  8. eeidfn says:

    Hi Dominick,
    For machine to machine flow (client credentials), is there an Open ID equivalent?
    Thanks

  9. Hi Dominick!
    Do you know real world native applications using OIDC Authorization Code – invoking browser for authorization? As I see most apps just ask login/password…

  10. Google/Android is a first party relationship wouldn’t you agree. Anyways – have a look around – browsers are everywhere when you look closer.

    • First party for sure :)) I was reading their documentation – how to implement google sign in. Seems they have much proprietary communication imlemented and it is not clear how it all works… (play services is not open source).
      Browser login really seems a nice and clear solution!

    • Dominick! One more question – with the browser approach how can we manage a 2FA scenario when SMS/Push mesage comes to mobile and the app automatically receives it (without needing the user to manually enter the code)?

  11. OK – interesting – well they must use some device specific APIs

    • Sure – your app must have permissions for that :) I think maybe on receiving sms/push by app we can reopen the browser (actual browser is waiting for 2FA code) with 2FA url and filled code parameter?

  12. Søren Olesen says:

    Hi, I’m pretty new to identityserver, and trying to figure out what to use in my setup. The setup consist of a client (SPA), an app-api, and a number of data-api’s. The client will access the app-api which will pull informationfrom the different data-api’s. In the client a user should be able to login using username/password, so I guess I should use HybridFlow here, but what should I use between the app-api and the data-api.
    My data-api is public, so I’d like to be able to control which app-api’s can access it, so I guess I need to use a Client Credentials flow? But I still need to know who the user is, so do I pass my userid in all calls, or do I use a combination of Client Credentials and Hybrid flow?? How is this normally done?

    • SPAs == implicit flow.

      For the server to server communication you can either forward the userid as payload – or use a token delegation approach.

      • Søren Olesen says:

        Just, userid as payload – or use a token delegation approach?
        or Client Credentials + (userid as payload – or use a token delegation approach)

        Token delegation, would that just be forwarding the Authorization header from the request to the app-api to the data-api?

        Is this the right place to ask for these tings, or is there a forum that I should use?

  13. Tomasz Stojecki says:

    Hi Dominick,
    I understand that IdSrv4 will apply PKCE when using Code or Hybrid grant types. Do you still recommend that we set the static client secret to something for Native Apps even though as you stated in Remark 2, it is no longer a secret? Or should we just set RequireSecret to false when registering the client? If former, can you elaborate on why that option with a static client secret is still a little better?

  14. Karl says:

    Hello Mr. Baier!

    Can you help resolve this dissonance?

    I understand that you generally recommend hybrid flow for native apps. However, other experts seem to object on the basis that when the id_token is returned on the front channel, it is not protected by PKCE and is at risk of being leaked.

    For example…

    John Bradley
    “While the hybrid response modes (they are not implicit) like code id_token are possible they may create security issues as the responses are not protected by PKCE.”
    https://github.com/openid/AppAuth-Android/issues/75#issuecomment-295021212

    William Denniss
    “Hybrid (and implicit) negate the PKCE protection required by RFC 8252 so it’s generally not recommended for native apps.”
    https://github.com/openid/AppAuth-iOS/issues/98#issuecomment-340058908

    I even see you and Mr. Denniss went back-and-forth on the topic briefly, where Mr. Denniss seemed to acquiesce that they “could consider official Hybrid flow support” in his AppAuth library, but as demonstrated in the above links, they appear to have made their decision against it.
    https://github.com/openid/AppAuth-iOS/issues/88#issuecomment-288309174

    Is this just a difference of opinion on an evolving technology whose strengths/weaknesses are still being resolved?
    Is there no ‘right’ answer at this point?
    …or am I missing something?

    (If you all could jump on a quick conference call and come to a consensus…yeah…that’d be great!) :)

    • I think we all more or less agree ;)

      1) PKCE is always required
      2) code is good
      3) code id_token gives you a little bit more (but for most clients it doesn’t matter)
      4) code id_token token is not recommended because the token cannot be protected by PKCE

      • Tarunpreet Ubhi says:

        but what about the “id_token” in “code id_token”. As I understand, the id_token is verifiable but not protected by PKCE in the Hybrid Flow. Doesnt this make the Hybrid Flow less secure than the Auth Code flow ?

      • id_tokens don’t need protection by PKCE. They already have built-in protection like signatures and nonces.

  15. obeydj says:

    suppose that we have a spa which talks to an api gateway, the gateway talks to a bunch on microservices, and we want to have sort of ‘zero trust network’, what are the flows that we can use in this scenario?
    knowing that:
    – the spa gives the end user a login page to authenticate with the gateway
    – each communication between the microservices must be after authentication

  16. Kirodge says:

    I’m new to OAuth 2.0/Open Id Connect.
    I found the following recommendations about implicit flow:

    IEFT OAuth 2.0 – security best current practice

    “Clients SHOULD NOT use the implicit grant …”
    “Clients SHOULD instead use the response type “code” (aka authorization code grant type)”

    https://tools.ietf.org/html/draft-ietf-oauth-security-topics-09#section-2.1.2

    IEFT OAuth 2.0 for Browser-Based Apps (Experimental Draft)

    “Public browser-based apps MUST implement the Proof Key for Code
    Exchange (PKCE [RFC7636]) extension to OAuth, and authorization
    servers MUST support PKCE for such clients.”

    https://tools.ietf.org/html/draft-parecki-oauth-browser-based-apps-00#section-6.1

    “Implicit Flow cannot be protected by PKCE[RFC7636] (which is required according to Section 6), so clients and authorization servers MUST NOT use the Implicit Flow for browserbased apps.”

    https://tools.ietf.org/html/draft-parecki-oauth-browser-based-apps-00#section-7.8

  17. Yes – ours does too. Still the session management aspect is completely undefined.

  18. Peval says:

    Hi,
    if the client is a Windows native app written by us, the same who provide the IdP and the API, would authotization code + PKCE flow still be the better choice over hybrid flow?

    Note that we started from ROPC (since the client is written by us and the user are managed by us), but then discarded it for security concerns.

    Thanks

  19. Confidential clients have secrets, public clients don’t. That hasn’t changes.

  20. mehdi hadeli says:

    Hi, In this post you said: ” If you want to use the access token purely on the server-side, this would result in unnecessary exposure of the token to the client. In that case, I would prefer the authorization code flow – or hybrid flow.”
    but when we use OpenIdConnectIdentication middleware with saveToken = true automatically save all token on the cookie and send them to front channel with ResponseType = code id_toekn and scope = {openid, profile, address}, and we couldn’t prevent send the access token to the front channel. how does this with hybrid flow or code flow? do have a sample for that?

Leave a comment