How to authenticate SPA users using oAuth2?
Asked Answered
E

2

9

Alright, I've spent several days looking for a proper solution on how to properly authenticate users when working with SPAs.

  1. I have my own website.
  2. I have my own API.
  3. I have my own Single Page Application.
  4. I have my own database of users.

The Goal: I need to get an access_token by providing a username and a password.

I looked at OAuth2 Implicit Grant, but it requires users to Approve/Decline the app after successful authentication. It doesn't work in my case since I own both the app and the API.

I looked at OAuth2 Password Grant, which is not perfect since I need to expose client_id/client_secret.

The reason I'm looking at OAuth2 is because the API will eventually be public.

Is there a standard way of doing this? My current options:

  1. Forget about OAuth2 and manually generate access_token when user POSTs username/password (in this case I'd have to introduce OAuth2 when API goes public)
  2. Use OAuth2 Password Grant and inject client_id/client_secret on the server, so just to keep client app very simple (also avoid all of those dev/staging/prod client_id/client_secret pairs)
Effie answered 6/1, 2017 at 0:10 Comment(3)
OAuth is intended for the cases where you don't own at least one of the resources (APIs) you need to call and need to ask the user for permissions to call use these resources on his/her behalf. To me it looks like you just need principal propagation between microservices.No
are you using a specific javascript framework or other dev environment?Marinna
The SPA template in Visual Studio 2017 has a working solution for this, maybe take a look at that?Tatterdemalion
G
7

Implicit Grant

You are right that Implicit grant type does not look appropriate. But I think your reason for not favoring it is incorrect because the approval step is not mandatory and in Spring OAuth 2 implementation (I don't know which implementation you are using) you can configure the Authorization server to auto approve authorization requests so that the approval step is skipped.

The reasons I think the "Implicit flow" is not suitable are

  1. ​The client authentication step by providing client secret and authorization code is missing. So less security.
  2. The access token is sent back as a URL fragment (so that the token doesn't go to the server) which will continue to stay in browser history
  3. If XSS attack occurs, the malicious script can very well send the token to the remote server

Resource Owner Password Credentials Grant

If the authorization server and the resource server are the same, I think this is a quick way of getting up and running. RFC 6749 in Section 4.3.2 says:

If the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), the client MUST authenticate with the authorization server as described in Section 3.2.1.

This means that the client authentication with client secret is not mandatory here. Now, for authorization code grant type, we need the client secret because the user provides his/her credentials directly to the authorization server and then when the client requests for the access token, it doesn;t have anything else other than the client secret to prove to the authorization server that this is a genuine request.

But in case of resource owner password credential grant type, the user has provided its credentials to the client itself and the client will then send these same user credentials for requesting access token. Therefore, the access-token request can be authenticated with the user credentials only and if we don't provide a client secret here, I don't think we are losing anything in terms of security.

So, you can definitely use password credential grant type in your SPA.

Authorization Code Grant

I think this should be the preferred option provided the client secret is not stored in the browser. After user authentication (and optionally user approval), the authorization server can redirect the browser to a server side endpoint with the authorization code in the URL. The server side end point will the request for the access token using the authorization code, client id and client secret (which is stored in the server side only). Once the access token is available, the server side endpoint can redirect (HTTP response code 302) the user to the SPA URL with appropriate cookies for CSRF protection and access token. Thus we are not storing the client secret in the browser.

By using authorization code grant type, you are basically making the solution more secured and generic. In future, if you want to do a single sign-on with a different SPA, you can do that easily by reusing the same authorization server with its integration with the authentication database (preferably an LDAP server).

For further details, refer to my StackOverflow answer here.

Gluey answered 31/12, 2018 at 14:50 Comment(0)
R
0

Building off what has been said already, I would recommend the 'Authorization Code Grant' but with the addition of the PKCE (Proof Key for Code Exchange / 'pixie') extension - for added security, regardless of whether you're implementing a 'public' or 'confidential' type client.

With PKCE, you don't need a client-secret for public clients (/it's kind of like generating a temporary client-secret at the very outset/beginning of each authentication attempt/instance - although even with PKCE for confidential clients you should ideally still use a client secret).

Reina answered 25/1, 2023 at 9:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.