Skip to content

Instantly share code, notes, and snippets.

@jawadatgithub
Last active February 11, 2024 23:15
Show Gist options
  • Star 62 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save jawadatgithub/638c11f08ecc0d76b05c to your computer and use it in GitHub Desktop.
Save jawadatgithub/638c11f08ecc0d76b05c to your computer and use it in GitHub Desktop.
Enrich IdentityServer3 Documentation with OIDC (OpenID Connect) and OAuth2 Flows section
Note for community:

A. IdentityServer3 docs, samples and source code use OIDC & OAuth2 terms interchangeably to refer to same thing in many areas. I think that's make sense because OIDC introduced as complement & extension for OAuth2.

B. IdentityServer3, STS, OP, OIDC server, OAuth2 server, CSP, IDP and others: means same thing (software that provide/issue tokens to clients) as explained in [Terminology] (http://identityserver.github.io/Documentation/docs/overview/terminology.html).

C. Grants and flows mean same thing, grant was the common term in OAuth2 specs and flow is the common term in OIDC specs.

D. This document will not focus on custom flow/grant.

E. [Important] Choosing wrong flow leads to security threat.

Part one: Flow Types and Origin

- OAuth2 standard specs defined 4 grants + extensibility for custom grant:

1. Authorization Code

2. Implicit

3. Resource Owner Password Credentials

4. Client Credentials

- OIDC standard specs Enriched Two OAuth2 flows (Authorization Code & Implicit) to support Authentication, and introduced new flow called:

5. Hybrid Flow

- IdentityServer3 Support all flows (below snippet copied from IdentityServer3 core) :
public enum Flows
    {
        AuthorizationCode = 0,  //introduced in OAuth2 then extended by OIDC.
        Implicit = 1,           //introduced in OAuth2 then extended by OIDC.
        Hybrid = 2,             //introduced in OIDC
        ClientCredentials = 3,  //OIDC specs didn't extend this flow.
        ResourceOwner = 4,      //OIDC specs didn't extend this flow.
        Custom = 5,
    }

Part Two: Explaining each of the five flow types using FAQ style

Q. What Does OAuth2 & OIDC Flows really mean?

A. its mechanism/approach/process (set of steps) that allow client to obtain token(s) from STS/OP through Endpoints. in other words, the whole life cycle of any Authentication & Authorization request is bound by one of the flows. so its essential to first understand the meaning of endpoints, clients, tokens and terms already explained in IdentityServer3 docs.

The main purpose of introducing multiple flow/grant types is to authenticate & authorize access to protected resources in various ways with different security credentials due to the variation of HTTP services based application architectures.

Q. Out of the 11 Endpoints implemented in IdentityServer3, Which are related to Authentication/Authorization request in all flow types?

A. In all flow types, any Authentication/Authorization request will be received by Authorization Endpoint or Token Endpoint only. so only two Endpoints handle the initial request. all other endpoints play important roles but not used during Authentication/Authorization request. and since flows focus on how Authentication/Authorization request being handled, this document will only focus on Authorization Endpoint & Token Endpoint.

- Authorization Endpoint: (in IdentityServer3 docs called: Authorization/Authentication Endpoint) Used to request:

  • identity token, access token, both tokens (implicit flow & hybrid flow).
  • authorization codes (authorization code flow & hybrid flow).

You either use a web browser or a web view to start the process.

- Token Endpoint: Used to programmatically request or refresh tokens (authorization code flow, hybrid flow, resource owner password credential flow, client credentials flow and custom grant types).

Note: All requests to the token endpoint must be authenticated - either pass client id and secret via Basic Authentication or add client_id and client_secret fields to the POST body. In other words, don't imagine that all authentication requests in all flows handled by Authorization endpoint, Authorization Endpoint will only provide authentication (identity token) for Implicit flow and Hybrid flow.

Note 2: OIDC authentication means Authenticating End User Identity ONLY, in OAuth2 all flows require authentication but not in the context of end user identity. (for example: Client Credential Flow is not meant at all with user identity (or OIDC in general) but its still include authentication.

[Important] ID tokens are meant for the client. Access tokens are meant for APIs. Don't send id tokens to APIs. ONLY case id_token sent to STS is EndSessionRequest but its optional.

Q. Which Flow Type in OpenID Connect (OIDC) / IdentityServer3 best fit the SPA use case?

A. Implicit flow designed for spa, client apps without server-side. Implicit flow is the default flow in IdentityServer3. although Implicit flow require redirectUri, it should be known that Google, Facebook, MS, Twitter, StackOverflow, GitHub, Yahoo...all follow the redirectUri concept. the main idea is any client (like web browser, native app) can't be trusted in Internet zone. in other words, if the SPA deployed in Intranet zone (on premise where all clients and users well known) (trusted environment) then its possible to honor seamless login experience over security. but since Intranet is pretty fast I still recommend to use Implicit flow for sake of consistency (would you like to make different branch of your code base if later on same SPA need to be deployed over internet?!)

Q. Which Flow Types designed to be used ONLY in trusted environment (like backend REST API/ micro-services isolated from internet, or owned servers/devices, in general: trusted OAuth2 clients)?

A.

  • Resource Owner Password Credential Flow (ROPCF) [it involve human: app show its own login page then pass user/pass... to STS].
  • Client Credential flow [machine to machine (API to API): supply client-id and secret].

Q. Authorization Code vs Implicit vs Hybrid vs Resource Owner Password Credential vs Client Credential Flows?

A. Authorization Code Flow:

  • Returns an authorization code that can then be exchanged for an ID token and access token.
  • Authentication request require client id and secret to retrieve the tokens.
  • Tokens not revealed to User Agent.
  • Support long lived access (through the use of refresh tokens).
  • Obtains the authorization code from the Authorization Endpoint.
  • All tokens are returned from the token endpoint.
  • Suitable only for clients who are capable of maintaining a client secret between itself and the STS securely (trusted environment or trusted OAuth2 Clients) (Example: server side MVC applications).
  • [Important] Avoid/Don't send access token to browser, after code obtained, webserver can talk with STS through the received code to obtain access token without browser involvement .

Implicit Flow:

  • Requests tokens without explicit client authentication, instead using the redirect URI to verify the client identity. (means in one round trip client can directly obtain identity token & access token).
  • Long lived tokens are not supported by design (refresh tokens aren't allowed for implicit flow). but in IdentityServer3 you can set/use long lived access tokens, or keep obtaining new ones through TokenManager JS helper library that can keep renewing tokens from an iframe (tradeoff between security and productivity).
  • Tokens revealed to User Agent.
  • All tokens are returned from the Authorization endpoint.
  • Does not use/communicate with the token endpoint.
  • Mainly used by web browser clients such as scripting clients, angularjs apps and SPA.

Hybrid Flow:

  • Combination of Implicit Flow and Authorization Code Flow.
  • 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).
  • Tokens revealed to User Agent.
  • Support long lived access (through the use of refresh tokens).
  • Obtains the authorization code from the Authorization Endpoint. (authorization code is mandatory in Hybrid Flow, otherwise Hybrid Flow will be clone of Implicit Flow).
  • Tokens are returned from authorization endpoint & token endpoint (totally depend on response_type value in the initial request to authorization endpoint) (if all tokens returned from token endpoint Hybrid Flow will be clone of Authorization Code Flow).
  • Hybrid flow can be spotted whenever you see a response type of code combined with some other response type, e.g. id_token or token (or both).
  • Usage varies 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 backend service) to request a refresh token and thus gaining long lived access to resources.
  • Typically used for clients that have their functionality distributed across a JavaScript part and a server-side part.
  • My definition for Hybrid Flow: enrich Implicit Flow with long lived access using refresh tokens feature of the Authorization Code Flow. AND, enrich Authorization Code Flow with obtaining identity token &/or access token in single round trip using Implicit Flow.

Resource Owner Password Credential Flow:

  • Pure OAuth2 Flow, OpenID Connect got nothing to-do with this flow because no end user identity involved (so id_token can't be obtained).
  • The user provide service credentials (username and password) directly to the application ( (e.g., login UI), which uses the credentials to obtain an access token from the service.
  • Supposed to be used by the applications that are owned by the resource server itself, and not any other third party.
  • Support long lived access (through the use of refresh tokens).
  • All tokens are returned from the token endpoint.
  • can be used to migrate existing clients using direct authentication schemes such as HTTP Basic or Digest authentication to OAuth2 by converting the stored credentials to an access token (allows for legacy applications to incrementally transition to OAuth2).
  • Doesn't support SSO with 3rd party STS/OP because for every STS/OP you need the user to enter his/her un/pass.
  • Should only be used when there is a high degree of trust between the resource owner and the client, and when alternative flows (like Authorization Code Flow) not available/viable.
  • This grant/flow type carries a higher risk than other grant types because it maintains the password anti-pattern OAuth2 protocol seeks to avoid.
  • The client could abuse the password, or the password could unintentionally be disclosed to an attacker (e.g., via log files or other records kept by the client) (e.g., if STS is twitter and they allow ROPCF for 3rd party apps, then the apps have access to the user twitter password and username, which already happened years ago).
  • STS/AS and client SHOULD minimize use of this grant type and utilize other grant/flow types whenever possible.

Client Credential Flow:

  • Pure OAuth2 Flow, OpenID Connect got nothing todo with this flow because no end user identity involved (so id_token can't be obtained).
  • refresh token SHOULD NOT be included/issued (since this flow not require user approval/involvement, new token can be easily obtained if the current expired).
  • Typically used when the client is acting on its own behalf (the client is also the resource owner) or is requesting access to protected resources based on an authorization previously arranged with the AS/STS (excellent for embedded services and backend applications).
  • MUST only be used by confidential clients.
  • All tokens (actually access token is the only token in this flow) are returned from the token endpoint.
  • Examples of when this might be useful include if an application wants to update its registered description or redirect URI, or access other data stored in its service account via the API.

Remark: MS OpenID Connect authentication middleware [Microsoft.Owin.Security.OpenIdConnect] [its client library for OIDC server] only support Hybird Flow. I think this is not a big deal since Thinktecture.IdentityModel provide OIDC and Oauth2 client library that support all flows.

Sources:

http://identityserver.github.io/Documentation/

https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Flows

http://wso2.com/library/articles/2014/06/open-id-connect/

http://leastprivilege.com/

http://oauthlib.readthedocs.org/en/latest/oauth2/grants/grants.html

https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2

http://tools.ietf.org/html/rfc6749

http://openid.net/specs/openid-connect-core-1_0.html

@dotcom9
Copy link

dotcom9 commented Feb 16, 2016

This is vital documentation, and it needs to be structured and written in a way that introduces developers with no prior knowledge of OIDC and Oauth2 to IdentityServer. Although the reference to these standards is important, there should be no need to refer to them to fully understand the subject of Flows in IdentityServer. And please, be consistent in naming and avoid the use of ellipsis (missing articles, verbs etc.) when writing: it makes understanding very difficult at times.

@jawadatgithub
Copy link
Author

Thanks you for the feedback, I will try to update the document when I get a chance. Regarding ellipsis, I scare to misguide the reader by giving him partial explanation, as you know security is difficult and it require deep understanding of details. yet I agree that easier to consume a document, reflects deeper understanding of the subject by the author.

@xiongtec
Copy link

Hello jawadatgithub, great work on the explaination. Did you have any intent to complete this documentation or is it completed?

@jjwilliams42
Copy link

Thank you for this!!!! I'm new to all this and figuring out which flows to use is driving me crazy.

@ghstahl
Copy link

ghstahl commented Aug 7, 2016

Very nice, however can you clarify why the Client Credential flow can't have a refresh token. i.e. refresh token SHOULD NOT be included.
I have a need for this, and am using the Resource owner flow as a work around. The work-around is having a custom UserService that simply takes the UserName/Password as fact and doesn't check it, assigns what is passed in as the subject and name. Client-Credentials are my real auth. Anyway, would really like a Credentials flow with refresh token, because I don't want to give out the client credentials to the end recipient.

@olivier-spinelli
Copy link

@ghstahl I'm afraid you're doing here a nasty thing. Clients are "confidential apps", applications that are explicitly registered in the STS so that they can interact with the STS. User (human being) and Client (applications) are really two different kind of beasts.

@Edu115
Copy link

Edu115 commented Apr 7, 2017

[Important] ID tokens are meant for the client. Access tokens are meant for APIs. Don't send id tokens to APIs. ONLY case id_token sent to STS is EndSessionRequest but its optional.

@jawadatgithub Thanks for the write-up! About this statement, I have a doubt. If I need API B to access the user claims, but proxied via another API A (client <-> API A <-> API B), and given that API B can only be accessed by API A, wouldn't passing the ID Token to API B be the best way to share the user's identity?

@jawadatgithub
Copy link
Author

@Edu115 the statement you doubting is fully compliant with OIDC specs. And before making API B obtain the user claims, API B must be authorized first, Right? so how would you handle that except making API A act as secondary STS?

the scope of this gist is to explain the flows, I recommend to ask your question in stackoverflow or https://github.com/IdentityServer/IdentityServer3/issues

@omerlh
Copy link

omerlh commented Apr 23, 2017

I have a question regarding implicit flow and SPA: I can understand why this flow is the most suitable for such client. The only issue I can think about - implicit flow means that the tokens will be stored in the browser url history. Isn't it better to use authorization code also in SPA, in a similar way to mobile? Meaning, adding JS code to replace the authorization code with token?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment