Sachin
Sachin

Reputation: 459

Spring security OAuth2 new Authorization Server with PKCE with React JS front end

Spring Boot

My application is mainly based on spring boot micro services. Currently it uses OAuth with password grant_type which is deprecated in the latest spring security authorization server release. For receiving JWT token, it stores client id and client secret in React JS frontend which is not secure and not recommended. Users need to register to access certain resources and application maintains login credentials in mysql DB

I am trying to upgrade spring security and want 'account service' to act as authorization server to issue JWT tokens.

  1. Am I correct in my understanding that I need to use authorization_code grand type with PKCE?
  2. If I use PKCE then I do not need users to provide passwords while registering, is that correct? Storing only username/email should suffice because users just need to pass client ID and code_challenge to get authorization code?

Upvotes: 0

Views: 3147

Answers (2)

ch4mp
ch4mp

Reputation: 12659

Authorizing client request

With OAuth2, clients (your React app) must authorize requests to protected resources, that is provide an access-token as Bearer Authorization header.

When acting on behalf of a user, clients should use authorization-code flow (with PKCE) to fetch such an access-token from authorization-server.

Also, use an OAuth2 client library in your React app. It will help you to:

  • redirect users to authorization-server
  • handle redirection back from authorisation-server with authorization code
  • exchange authorization code for tokens (access, refresh and ID)

Some libs even handle:

  • access token silent refresh before it expires
  • request Authorization to configured routes (add access token as header)
  • automatically trigger login when a user tries to access protected parts of the app.

I have not enough experience with React to recommend a specific lib, but you can search with "OpenID", "OIDC" or even "OAuth2" keywords

Configuring spring REST APIs

REST APIs secured with OAuth2 are "resource-servers". You can use spring-boot-starter-oauth2-resource-server directly as done in the first of those tutorials, but it is quite some Java conf.

Instead, you can use one of the spring-boot starters from the same repo. They are thin wrappers around spring-boot-starter-oauth2-resource-server with sensible defaults and most security conf from properties:

<dependency>
    <groupId>com.c4-soft.springaddons</groupId>
    <!-- replace "webmvc" with "webflux" if your app is a servlet -->
    <!-- replace "jwt" with "introspecting" to use token introspection instead of JWT decoding -->
    <artifactId>spring-addons-webmvc-jwt-resource-server</artifactId>
    <!-- this version is to be used with spring-boot 3.0.0-RC2, use 5.x for spring-boot 2.6.x or before -->
    <version>6.0.5</version>
</dependency>
@EnableMethodSecurity
public static class WebSecurityConfig { }
com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443/realms/master
com.c4-soft.springaddons.security.issuers[0].authorities.claims=realm_access.roles,ressource_access.some-client.roles

com.c4-soft.springaddons.security.cors[0].path=/some-api

Configuring the gateway

Basically, nothing to do in regard to authentication and OAuth2: inbound requests to secured resources should have an authorization header already and resource-servers will respond with 401 if authentication is missing or invalid (expired, wrong issuer, ...) or 403 if access is denied (valid identity but not allowed to access that resource)

authorization-server

Any OAuth2 authorization-server would do, but you might choose an OIDC implementation.

Authorization-server will handle users registration, login and logout. It will issue access, refresh and ID tokens, using mainly:

  • authorization-code flow for clients acting on behalf of a user
  • client-credential flow for trusted programmatic client acting in their own name (not on behalf of a user)
  • refresh-token: if offline_access scope is requested when authenticating (with any flow), a refresh-token is returned in addition to access-token and can be used to silently get a new access-token when current expires (or just before it does)

You can use Spring authorization-server framework to build your own authorization-server, but could also prefer to pick one "off the shelf": there are plenty out there with a lot of features implemented

  • connect to LDAP and "social" identity providers (Google, Facebook, Github, etc.)
  • enhance security with multi-factor authentication
  • provide with admin UI for stuff like user roles or tokens content
  • ...

And this either on premise (Keycloak is a quite popular sample) or SaaS (like Auth0 and many others: almost any cloud provider has its own solution).

Upvotes: 2

witosh
witosh

Reputation: 129

  1. Am I correct in my understanding that I need to use authorization_code grand type with PKCE?

The newest version of Spring Security mode introduces a new project for the Authorization server in the scope of Spring Security:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-authorization-server</artifactId>
    <version>0.3.1</version>
</dependency>

The authorization server from spring implements OAuth2.1 where as you mentioned, both PASSWORD and IMPLICIT grant types were removed comparing it to OAuth 2.0. Gran types supported in OAuth 2.1: 1

  • Authorization code + PKCE
  • client credentials
  • device grant type

OAuth 2.1 provide authorization code + PKCE grant type but it's a little bit different from the previous.

"The key difference between the PKCE flow and the standard Authorization Code flow is users aren’t required to provide a client_secret. (...) In place of the client_secret, the client app creates a unique string value, code_verifier, which it hashes and encodes as a code_challenge. When the client app initiates the first part of the Authorization Code flow, it sends a hashed code_challenge."

2

That type of grant type is recommended for SPA application so if you want to use the newest version of spring security you need to use it, because e.g. client credentials are reserved for machine-to-machine communication when one service needs to communicate with another service without of user's knowledge.

  1. If I use PKCE then I do not need users to provide passwords while registering, is that correct? Users need to authenticate themselves and that's a part of this grant-type flow.

Storing only username/email should suffice because users just need to pass client ID and code_challenge to get an authorization code? ClientID and generated code_challenge (should be generated by the client) is something that identifies the client not the resource owner, so user while authorized shouldn't provide this type of info.

Upvotes: 1

Related Questions