SPA: Access token for multiple APIs

Hi,

We have a set of microservices using Spring Boot framework. Each microservice is represented by a distinct API in Auth0, which means unique audience per API. The initial benefits of this approach were:

  1. JWT generated for a given audience can’t be used on a different API.
  2. Developers can work independent from each other when defining scopes and new APIs.

The challenge we are facing now is having a SPA where users login and access functionalities according to their roles. The users authenticate for a particular audience (API) using the granted type http://auth0.com/oauth/grant-type/password-realm. This SPA needs to communicate with other APIs from the same ecosystem different to the one the user logged in.

We are aware of the following facts:

  1. Auth0 supports RBAC for API authorization and permissions can be directly assigned to users or via roles containing the required permissions.
  2. Auth0 doesn’t grant access tokens targeted for multiple audiences
  3. Auth0 provides a guideline to represent multiple APIs using a single logical API in Auth0 but the aforementioned article doesn’t fit our needs because each API has its own audience and the security configuration for Spring Boot (other frameworks supported by Auth0 as well) requires the audience and issuer to verify the integrity of the token.

JwtWebSecurityConfigurer. forRS256(this.audience, this.issuer)

The question:
How can we proceed with the SPA application in order to access multiple microservices behind the scenes – without the user having to do any further authentication except for the initial login?

1 Like

Hello @howard.em,

Welcome to the Community. I believe our dev team had the same issue. In the end they decided to go back to Auth0 to change access tokens as needed. They considered the Auth0 suggested model you linked to, but decided against it for their own reasons.

Here is a workaround to make the same path in the backend to work with two apps (SPA and M2M+API)

  @Order(3)
  @Configuration
  public static class ApiConfigurationAdapter extends WebSecurityConfigurerAdapter {

    @Value(value = "${auth0.spa.clientId:}") private String spaClientId;
    @Value(value = "${auth0.m2m.clientId:}") private String m2mClientId;
    @Value(value = "${auth0.api.identifier:}") private String apiIdentifier;
    @Value(value = "${auth0.issuer:}") private String issuer;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

      AuthenticationProvider ap = new AuthenticationProvider() {

        private final JwkProvider jwkProvider = new JwkProviderBuilder(issuer).build();
        private final JwtAuthenticationProvider spaAuthenticationProvider = new JwtAuthenticationProvider(jwkProvider, issuer, spaClientId);
        private final JwtAuthenticationProvider m2mAuthenticationProvider = new JwtAuthenticationProvider(jwkProvider, issuer, apiIdentifier);

        @Override
        public boolean supports(Class<?> authentication) {
          return spaAuthenticationProvider.supports(authentication); //or m2mAuthenticationProvider (doesn't matter)
        }

        @Override
        public Authentication authenticate(Authentication authentication) {
          if (String.format("%s@clients", m2mClientId).equals(authentication.getName())) { //workaround
            return m2mAuthenticationProvider.authenticate(authentication);
          } else {
            return spaAuthenticationProvider.authenticate(authentication);
          }
        }
      };

      JwtWebSecurityConfigurer.forRS256(null, null, ap).configure(http).cors().and().csrf().disable().authorizeRequests().antMatchers("/admin/**", "/facade/**").authenticated();
    }
  }
1 Like

Thanks for sharing it with the rest of community!

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.