2

Background

We have an existing traditional webapp (Wicket/Java/Spring/Tomcat) that we are incrementally migrating to a Vue.js application/SPA. So when the user navigates to certain parts of the application we serve the SPA which the user interacts with until they navigate to a old part of the application again.

All user authentication is currently handled by the traditional webapp which results in a tomcat session (JSESSIONID cookie).

The SPA currently talks to the API on the main java monolith application. This is the same application serving the traditional webapp. So currently we handle authentication by checking for the presence of the JSESSIONID cookie/tomcat http session in the request from the SPA.

       ┌──────────────┐
       │  Browser     │
       │              │          ┌────────────┐
       │  ┌──────┐    │          │  Monolith  │
 ──────┼─►│ HTML │◄───┼─────────►│    java    ├──────────────┐
       │  └──────┘    │          └────────────┘              ▼
       │              │             ▲             ┌──────────────────────┐
       │ ┌─────────┐  │             │             │ OAuth2 Authorization │
       │ │   SPA   │◄─┼─────────────┘             │       Server         │
       │ │ (VueJs) │  │                           └──────────────────────┘
       │ └────┬────┘  │                                      ▲
       │      │       │                                      │
       └──────┼───────┘               ┌──────────────┐       │
              │                       │ Microservice │       │
              └──────────────────────►│     java     ├───────┘
                                      └──────────────┘

Requirement

We are building new microservices (with APIs) that we wish the SPA to be able to talk to. So our approach of sharing the JSESSIONID cookie is not going to work.

We'd like to use OAuth2 to protect our new microservices meaning that they will require valid access tokens for all incoming requests.

Question

All the documentation and examples we've found are concerned with implementing the standard solutions whereby you choose the OAuth2 grant flow you want to use (implicit or authroization code with PKCE) and get the SPA to prompt the user to authenticate.

This is not going to work for us while we are still in this hybrid situation and all user authentication is handled by the traditional webapp.

  • What are some approaches that people use in situations like these?
  • How can the SPA be given enough information when it is loaded in order to make (pre)authenticated calls to the new microservice API?

We are happy to consider moving the traditional webapps login flow to an OAuth based flow but still aren't clear how to solve the problem with the SPA.

Oliver Henlich
  • 283
  • 4
  • 13

2 Answers2

0

If all your apps are OAuth2, it's likely that you choose an OIDC authorization-server and almost all have SSO (single sign-on) features: when users authenticate (with authorization-code + PKCE flow), they have a "session" opened on authorization-server and can have subsequent authentications happen silently (only the very first authentication for each client can require explicit consent).

In other words, with SSO, your users would authenticate once for all clients (legacy app and new Vue one).

Be sure to pick Certified OpenID Connect Implementations for each of your client frameworks.

ch4mp
  • 6,622
  • 6
  • 29
  • 49
  • Thanks @ch4mp. So you are saying change our traditional webapp to use OAuth during the authentication flow so that a session (cookie) is setup for the browser in the Authorization Server (AS). Then have the SPA use the authorization code + PKCE which should cause no authentication prompts because the AS cookie will be passed in the calls? – Oliver Henlich Jan 11 '23 at 20:51
  • Yes authorization-servers usually keep sessions (with cookies or whatever), so all authorization-code requests from the same browser session can benefit silent login (if the user already consented scopes for the requesting client) – ch4mp Jan 11 '23 at 21:56
  • I think this solution is just related to UI? You are right in term of user authentication, but it doesn't solve issue with micro service access. – MSZMC Jan 12 '23 at 08:00
  • Of course it does. Each OAuth2 client will get its own access-token and all clients will use those tokens to authorize their requests (set an access-token as Bearer authorization header) to resource-servers (micro-services) – ch4mp Jan 12 '23 at 12:13
  • This is wrong. OIDC can be used with authorization-code (and should be used with PKCE in case of browser clients). This is the way I use it with Angular clients and https://github.com/damienbod/angular-auth-oidc-client – ch4mp Jan 12 '23 at 12:39
  • sorry I was wrong in terms of PKCE, you are right, it is true if you want to authenticate user even with public client, but still looking at @OliverHenlich current implementation and recommendation related to web browser and OAuth I would say that existing session authentication + access token and refresh token on same service that handle session is more natural solution. – MSZMC Jan 12 '23 at 12:48
  • It is also exposed to CSRF attacks, poorly scales and reduces fault tolerance: when a resource-server with sessions is shut down, all sessions are lost (access-tokens on clients aren't). Also, with several resource-server nodes, if sessions are used, a smart load-balancer must be used to route all requests from a given client to the node where the session is kept. – ch4mp Jan 12 '23 at 13:03
0

In addition to previous answer, OIDC is correct choice, because you can still have user session that will be created during OIDC flow: https://openid.net/connect/

In OIDC flow id token, access token and refresh token are returned, but id token is used only once to establish user session.

Access token and refresh token can be saved on backed service(I.e some gateway) responsible for OIDC communication and user session creation. Then based on user session you can find those tokens and use in call to microservice when needed.

It is important to understand whole concept behind oauth especially in scenario with web application. I recommend to read those information to understand whole picture: https://www.ietf.org/archive/id/draft-ietf-oauth-browser-based-apps-10.html

MSZMC
  • 97
  • 1
  • 8
  • Thanks @MSZMC. So you are saying 1) Change the traditional webapp to use OIDC during user authentication to get his ID token, access and refresh tokens and store somewhere in the backend? 2) Introduce an API api gateway and have it add the access token to all API calls received from the SPA which it retrieves from the backend location they were stored? 3) The SPA remains unaware of all OAuth tokens? – Oliver Henlich Jan 11 '23 at 20:13
  • Yes, thanks to this, user authentication(based on session) is performed in one service that handle OIDC and then based on given access token you can request any service that you want. In first step it is authentication with session and then with call to micro service you don't care about authentication (who make the request), but about authorisation (what roles are in access token). – MSZMC Jan 12 '23 at 08:03
  • You don't have to use a Gateway and sessions to secure requests to resource-servers with OIDC. The session can be maintained by authorization-server only, and then OIDC client libraries can handle access-token acquisition, persistence, refreshing and insertion in authorization header (all that on clients, without any gateway) – ch4mp Jan 12 '23 at 12:20
  • In other words: no session required on resource-servers (even in case of an API gateway). User state (identity and authorities) can be held in access token instead of session and this access tokens can be maintained on clients by [proper libraries](https://openid.net/developers/certified/) – ch4mp Jan 12 '23 at 12:23