12

I am trying to understand how to implement an OAuth 2 Authorization Code flow when having both a single page JS app and a REST API. The aim is to secure access to the REST API by offloading authentication to the OAuth provider.

Currently my flow looks like:

1)

+--------------------+               +----------------+
| JS Single Page App | - redirect -> | OAuth Provider | - user enters credentials
+--------------------+               +----------------+

2)

+----------------+                                   +----------+
| OAuth Provider | - redirect with temporary code -> | REST API |
+----------------+                                   +----------+

3)

+----------+                                      +----------------+
| REST API | - request access token using code -> | OAuth Provider |
+----------+ <- return access token ------------- +----------------+

What should I do now? My current understanding is that I should redirect the user upon receiving the access token to a page that will load the JS single page app again. But should I share the access token with the single page app and use the presence of it to authenticate any request hitting my REST API, or is better to create a separate identifier and maintain a server-side mapping between new-identifier->access_token? Either way what would be the best way of transferring whichever identifier to the client? I would prefer not maintain any session and not have the identifier turn up in the URL bar of the redirected page. The only thing I can currently think of would be to create a temporary cookie that the single page app would read and then erase, but somehow that feels a bit clunky.

Anvar Karimson
  • 223
  • 1
  • 2
  • 4

2 Answers2

12

Firstly, and to be very clear, OAuth 2 is not an authentication protocol. If you wish to know the identity of the user, there are other protocols designed to solve this problem, such as OpenID Connect. If you intend to use OAuth 2 for the purpose of authorizing access to your protected resources, continue reading.

To answer your direct question: you appear to be using the Authorization Code Grant flow:

 +----------+
 | Resource |
 |   Owner  |
 |          |
 +----------+
      ^
      |
     (B)
 +----|-----+          Client Identifier      +---------------+
 |         -+----(A)-- & Redirection URI ---->|               |
 |  User-   |                                 | Authorization |
 |  Agent  -+----(B)-- User authenticates --->|     Server    |
 |          |                                 |               |
 |         -+----(C)-- Authorization Code ---<|               |
 +-|----|---+                                 +---------------+
   |    |                                         ^      v
  (A)  (C)                                        |      |
   |    |                                         |      |
   ^    v                                         |      |
 +---------+                                      |      |
 |         |>---(D)-- Authorization Code ---------'      |
 |  Client |          & Redirection URI                  |
 |         |                                             |
 |         |<---(E)----- Access Token -------------------'
 +---------+       (w/ Optional Refresh Token)

This flow is optimized for confidential clients: clients which can keep a secret from the end-user and any third-party that might be trying to gain access to the protected resources. In the case of a javascript application running in the client's browser, you cannot keep a secret - all the code is there and simply breaking into it with the browser's debugger reveals all the secrets.

Instead, there is the Implicit Grant flow, specifically optimised for clients like yours. The RFC even uses JavaScript running in a browser as its example of a client intended to use this flow.

 +----------+
 | Resource |
 |  Owner   |
 |          |
 +----------+
      ^
      |
     (B)
 +----|-----+          Client Identifier     +---------------+
 |         -+----(A)-- & Redirection URI --->|               |
 |  User-   |                                | Authorization |
 |  Agent  -|----(B)-- User authenticates -->|     Server    |
 |          |                                |               |
 |          |<---(C)--- Redirection URI ----<|               |
 |          |          with Access Token     +---------------+
 |          |            in Fragment
 |          |                                +---------------+
 |          |----(D)--- Redirection URI ---->|   Web-Hosted  |
 |          |          without Fragment      |     Client    |
 |          |                                |    Resource   |
 |     (F)  |<---(E)------- Script ---------<|               |
 |          |                                +---------------+
 +-|--------+
   |    |
  (A)  (G) Access Token
   |    |
   ^    v
 +---------+
 |         |
 |  Client |
 |         |
 +---------+

You should read the RFC for details of how this flow works, but the general concept of the flow is to no longer require the use of an authorization code; instead the client is directly given the access code.

This comes with the drawback that when the code is no longer valid, the client must request the resource again - there is no way to "remember" the authorization grant for a client which is unable to keep a secret. This is an intentional decision made by the OAuth authors to improve the security of clients of this nature.

Paul Turner
  • 236
  • 2
  • 6
  • Hi, thank you for the response. I am indeed using the Authorization Code Grant flow as I have a server-side part of my application. In this case the access_token would never directly be shared with the client so the attack highlighted in the referenced article would not be possible, or so I believe. But regardless, you are absolutely correct in that OAuth2 is not an authentication framework. I will look into using OpenID Connect instead! – Anvar Karimson Sep 19 '14 at 08:51
  • If you run into similar problems getting an OpenID Connect implementation to work, ask a question about it and add a link to it in a comment here - I'll do my best to assist. – Paul Turner Sep 20 '14 at 22:33
1

I'm not sure if I understand your scenario correct. If you only want to secure your RESTful API calls from a javascript client with OAuth then Tragedian's answer about the implicit grant type is absolutely correct. This means that you have a clear segregation of UI and data:

  • The UI (i.e. JS single page application) can be loaded without any form of authentication/authorization
  • The data (i.e. RESTful API calls) are secured with access tokens AFTER beeing authorized by the authorization server

If you have a different scenario please describe it more precisely. You mention something of a backend part of the application which also relies on OAuth and which is capable of storing sensitive data. This would mean that you have, beside the JS single page app, a DIFFERENT client (in OAuth language)...

pfust75
  • 425
  • 7
  • 9
  • Yes, using the implicit grant type is definitely correct, as is using the authorization grant type. They both come with tradeoffs, and in this case I prefer to use the authorization grant one. My question was whether I could share the access token with the client (ui) or whether I had to generate a new identifier. But as Tragedian correctly pointed out, OAuth2 is not meant for authentication, and I should be using OpenID Connect instead. – Anvar Karimson Sep 22 '14 at 08:06