We have a Web Application that mints an internal JWT used for authentication along with a secure cookie. As the organization has been moving to Okta there is an ask to integrate that login flow into our app.
Our current workflow:
It poses a lot of challenges. After some analysis, I think I see how I want to approach it:
/sso-login
, passing in the authorizationCode as a parameter{okta-server}/token
endpoint to get the okta bearer token and parse the results to get userName
Does this flow make sense? Is it safe? Most literature and examples I see tend to involve SPA or integrate everything in the BE.
Because of the opaqueness of the Spring oauth2 integration I am favoring avoiding that for now and manually constructing my POST call to the /token
endpoint.
According to latest recommendations, OAuth2 clients (applications to which tokens are delivered and which store those tokens) should be "confidential" (secured with some sort of secret). This requires it to run on a server you trust (neither Javascript based apps in a browser nor mobile apps can keep a secret).
This means that, to follow OAuth2 best practices, your React app should not be an OAuth2 client nor have access to tokens. Its requests to the backend should be authorized with session cookies (which requires protection against CSRF attacks).
A noticeable exception being Next.js apps using the NextAuth lib which handles authorization code and tokens storage server side (node) with a confidential client, and use session cookies for communication between the browser and server parts of the app.
The solution I detail in this Baeldung article, is to configure a spring-cloud-gateway
instance as an OAuth2 BFF (runs authorization code and refresh token flows, stores tokens, and bridges between cookie-based authorization (requests from the frontend) and Bearer-based authorization (requests forwarded to downstream resource servers). This is the exact same pattern as what NextAuth does for Next.js, but probably more scalable and easier to instrument with observability (also works with any frontend framework, not just Next.js).
When user authentication is required:
authorization_code
flowWith this pattern, requests are protected with:
If you inspect about any serious OAuth2 app with your browser debugging tools (Gmail, Facebook, LinkedIn, etc.), you'll find session cookies but no Authorization
header with a Bearer token. You won't even find an OAuth2 token anywhere in your browser. The reason is that they apply this pattern...