Kotlin Spring Security Using JWT Token from Azure AD B2C

Viewed 28

Introduction

I've got a React SPA which uses Azure B2C to authenticate. Now I want to authenticate the Frontend to the backend using an access token. In an early state of development the user only needs to be authenticated. Role-based access will be implemented later.

Setup

application.properties:
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://login.microsoftonline.com/<Directory (tenant) ID>/v2.0/

WebSecurityConfiguration.kt:

@Configuration
@EnableWebSecurity
class WebSecurityConfiguration : WebSecurityConfigurerAdapter() {

    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        http
            .cors()
            .and()
            .securityContext().disable()
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .antMatchers("/error").permitAll()
            .anyRequest().authenticated()
            .and()
            .oauth2ResourceServer().jwt()
    }
}

Problem

Link of the token validator

First of all I'm not even sure if the link for the issuer is correct.
https://login.microsoftonline.com/<Directory (tenant) ID>/v2.0/.well-known/openid-configuration responds with token_endpoint_auth_methods_supported.
To my understanding the token sent to the backend should be validated through an trusted Oauth2 validator (My Tenant of Azure AD B2C in my case).

Spring setup

As far as I understand it, this should do the trick (followed this documentation). But the only response I get is 401 Unauthorized. I tried a lot of different links for the issuer and a lot of different security configurations. But it feels like I'm just try and error without any progress.

Lack of transparency

With the log-level set to debug, the only log I get from spring when trying to access the API is this one:
Securing GET /subscriptions?eCustCode=someCode

How I test the access

I'm testing the authorization using Postman with a Access Token using Bearer Token as Authorization Type and Bearer <tonken> as the actual token value.

Additional

I know WebSecurityConfigurerAdapter is deprecated and FilterChain should be used instead to authenticate. But I don't understand the concept completely, nor did I find any useful example or tutorial using kotlin being anything near my setup.

I found this question on stack overflow but didn't manage to get the authentication running.

UPDATE

After analysing with log-level TRACE the following exception is being thrown:
JwtDecoderInitializationException: Failed to lazily resolve the supplied JwtDecoder instance
IllegalArgumentException: Unable to resolve the Configuration with the provided Issuer of
To me this looks like the URL really is wrong. Question now is, what should the correct issuer-uri look like?

With some links I get a different error:
The Issuer <link of issuer-uri> provided in the configuration did not match the requested issuer <link of issuer-uri>

LATEST UPDATE

Using the iss-value of the token as issuer-uri leads to the following exception:
BadJWSException: Signed JWT rejected: Invalid signature
This is strange to me, since I login via B2C and use the generated token which i receive from msal directly.
jwt.io also tells me the signature is invalid. Seems like there is a misconfiguration while retreiving the token.

I now managed to authenticate using the ID-Token if I declare the iss-value within the token as the spring.security.oauth2.resourceserver.jwt.issuer-uri in the application.properties.
The ID-token's signature is valid hence I can use it. Following the documentation of Microsoft ID-tokens should not be used to authenticate against an API. So I'm still looking for a solution to fix the signature of my access tokens.

I'll post a solution if I find any. If you have any adivce on finding the solution, please tell me.

1 Answers

Please have a look at the note at the end of Specifying the Authorization Server in Spring-security doc and check if your authorization-server is compatible with setting issuer-uri only:

To use the issuer-uri property, it must also be true that one of idp.example.com/issuer/.well-known/openid-configuration, idp.example.com/.well-known/openid-configuration/issuer, or idp.example.com/.well-known/oauth-authorization-server/issuer is a supported endpoint for the authorization server. This endpoint is referred to as a Provider Configuration endpoint or a Authorization Server Metadata endpoint.

If not, you could try to set both

  • issuer-uri with the exact value you have as iss claim of your access-tokens
  • jwk-set-uri with https://login.microsoftonline.com/<Directory (tenant) ID>/v2.0/keys (not sure about the URI for the JWK-set in your case, check the JSON at https://login.microsoftonline.com/<Directory (tenant) ID>/v2.0/.well-known/openid-configuration or the doc if path isn't /keys)

PS

For the "later state" (when you'll want role based access control), have a look at this: https://github.com/ch4mpy/spring-addons/tree/master/samples/tutorials

Related