20

I'm building a Single-Page App (SPA) and a RESTful API. The API needs security - certain users can only make calls to certain endpoints. I have an external Identity Provider (IdP (Okta)) that I want the user to authenticate with using the OpenId Connect protocol. I'm trying to clarify the correct steps for authentication and authorization of the SPA to the RESTful API. The two flows I've been looking at are the Authorization code flow and the Implicit flow.

If I was to go with Implicit flow, then the steps would be:

  1. The user visits the SPA, which redirects the user to the IdP to sign-in.
  2. After the user signs in, the IdP returns the user to the SPA with an access token and ID token.
  3. (This is the step I'm unsure about) Each time the SPA makes a request to the RESTful API, it passes the access token and ID token along with the request, which the RESTful API validates and then checks the user has authority to access the particular endpoint. If it does it returns the result, otherwise the user is unauthorized.

If I was to go with the Authorization Code flow, then the steps would be:

  1. Same as above step 1.
  2. After the user signs in, the IdP returns the user to the SPA with an authorisation code.
  3. (Again, the step I'm unsure is correct) Each time the SPA makes a request to the RESTful API, it passes the authorization code along with the request, which the RESTful API then exchanges (along with a client secret) with the IdP for an access token and ID token. It uses these to check if the user can access the particular endpoint. If it does it returns the result, otherwise they're unauthorized.

I think the implicit flow is the one to use in this scenario, but do I have the steps correct? Particularly step 3, sending two tokens in every request, doesn't seem right. But I think I need both tokens to validate and determine the user. Help appreciated!

Steve
  • 313
  • 1
  • 2
  • 7

1 Answers1

18

Here is the difference between Implicit Flow and AuthCode Flow:

Implicit Flow

NOTE: As of April 2019, the Oauth Working Group no longer recommends the use of Implicit Flow for most cases because there are better, more secure ways to accomplish the same things.

  1. User navigates to SPA, which redirects user to IdP to sign in.
  2. User signs in (and authorizes the application, if needed).
  3. IdP returns user to SPA with Access Token and ID Token.
  4. JavaScript code in SPA stores the Access Token and ID Token in the browser's localStorage and sends the Access Token to the REST API server for every request it makes (usually as an Authorization: Bearer <access token> header).
  5. If needed, REST API Server checks the validity of the Access Token by talking to the IdP. (Often, signing the token in the IdP and verifying that signature will be enough, and no communication is actually necessary.)

Authorization Code Flow

  1. User navigates to SPA, which redirects user to IdP to sign in.
  2. User signs in (and authorizes the application, if needed).
  3. IdP returns user to SPA with Authorization Code.
  4. JavaScript code in SPA sends the Authorization Code to a login endpoint on the REST API Server.
  5. The REST API Server sends a request to the IdP Server containing the Authorization Code (and usually also a Client ID and Client Secret which identify the REST API Server to the IdP server).
  6. The IdP validates the Authorization Code and sends the Access Token and ID Token to the REST API Server.
  7. The REST API Server stores the Access Token and ID Token in its memory, and sends its own Session Token back to the SPA.
  8. For every request the SPA makes to the REST API Server, it includes the Session Token which the REST API Server gave it. If the REST API Server needs to request resources from another server, it uses the stored Access Token to make that request.

You can see from here that the AuthCode flow is significantly more complicated than the Implicit flow, but with the benefit that the Access Token is never stored in the user's control.

However, the main point of storing the token in this case is not for your own authentication, but for the case where the REST API Server needs to talk to other services, such as Google, Facebook, Twitter, etc.

If you are only using OpenID Connect for logging into your own REST API Server, but then the credentials never need to be used by the server itself, implementing Implicit Flow is significantly easier, and implementing AuthCode flow doesn't actually gain you anything.

Moshe Katz
  • 1,331
  • 1
  • 11
  • 17
  • Thanks for the post Moshe. Unfortunately with Implicit Flow the IdP I'm using does not offer an access token that I can validate with a key. I can only think to send it to the IdP's UserInfo endpoint to validate it each time, which doesn't seem ideal. And the issue I have with the Authorization Code Flow is that session is stored in the RESTful API but it should be stateless. The only way around that is to get the Access and ID Token each request... maybe that is not such a bad idea. – Steve Jul 20 '16 at 03:14
  • 1
    @Steve Maybe you should generate your own authorization token (using JWT, or similar) once you have validated the user. You don't need to store the JWT on the server, only validate it on each request. I am actually doing exactly that fit a project with multiple authentication backed providers - the user gets a token from one of the backends (Google, Facebook, Shibboleth, OpenID, etc.) and then passes that to me. I then give the user a JWT which is valid for a short time. The user can keep renewing the JWT every hour; after an hour of not renewing the JWT, it expires. – Moshe Katz Jul 20 '16 at 03:20
  • Interesting idea. I never had in mind building my own Authentication Server to hand out JWT's. If I can avoid it I will but there are solutions like IdentityServer that look a good fit for this. I don't suppose you did that in ASP.NET? If so I'd be keen to see the source if its available. – Steve Jul 21 '16 at 00:03
  • Sorry, I did it in PHP. These might help you though: http://odetocode.com/blogs/scott/archive/2015/01/15/using-json-web-tokens-with-katana-and-webapi.aspx http://www.developerhandbook.com/c-sharp/create-restful-api-authentication-using-web-api-jwt/ http://stackoverflow.com/questions/23674613/using-jwt-to-implement-authentication-on-asp-net-web-api – Moshe Katz Jul 21 '16 at 00:24
  • @MosheKatz : I'm late to the party but, how do you revoke access for a user. F.e. if the user is placed on inactive on the Identity provider, how will you revoke the user access if the client keeps renewing the JWT token? – Housy May 12 '17 at 07:47
  • @WouterHuysentruit You keep a blacklist of revoked tokens. When the client next goes to renew, they aren't allowed to do so because the token they have is already on the blacklist. – Moshe Katz May 12 '17 at 11:30
  • @MosheKatz Does it make sense to use the Authorization Code Flow if you want to allow "remember my login" behavior? The server can store the access token and refresh token and automatically refresh on a new login, correct? – Ralph Dec 19 '17 at 14:27
  • Hi, wrt https://openid.net/specs/openid-connect-basic-1_0.html#CodeFlow it looks like in Step4, the SPA application doesn't send the code to REST API server rather to the IDS to get access token and ID token. Please clarify – Gopi Aug 12 '19 at 05:56
  • @Gopi In this case, the OpenID `Client` is not actually the end user; the `Client` is the application server. That is why the flow is different. – Moshe Katz Aug 12 '19 at 15:17
  • @MosheKatz 'The REST API Server stores the Access Token and ID Token in its memory, and sends its own Session Token back to the SPA' - could you give an example of how exactly this can be implemented? If it's a REST Api, then we could probably store the access token in the database, along with the associated session token generated by the REST Api? – user4205580 Aug 25 '19 at 15:29
  • @moshekatz "there are better, more secure ways" can you name one? sorry to bother, but my english is not good, hard to read that ietf document. – WestFarmer May 07 '22 at 06:46