I have what I thought was a typical application with React front end and Spring boot as the backend. I’m trying to setup security to use Azure active directory to authenticate and authorize users. Authentication works but authorization doesn’t
The UI part is simple and works, I’m using MSAL to authenticate and get the account. I can see in console log that everything is ok from that perspective. I also see the following in the token request/response:
https://login.microsoftonline.com/*{XX}*/oauth2/v2.0/token
scope: "User.Read profile openid email"
token_type: "Bearer"
The issue I’m having is in the backend, I’m getting the following error:
Failed to authorize filter invocation [GET /api/document/list] with attributes [hasAuthority('SCOPE_User.Read')] using AffirmativeBased [DecisionVoters=[org.springframework.security.web.access.expression.WebExpressionVoter@470b5213], AllowIfAllAbstainDecisions=false]
Sending JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@43ebd8ff, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[]] to access denied handler since access is denied
As you could see for some reason on the resource server we are not getting the scopes the user has access to (i.e. User.Read)
Spring Security setup:
@Configuration
public class SecurityConfig {
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http.authorizeRequests((authorize) -> authorize
.mvcMatchers("/**").hasAuthority("SCOPE_User.Read") // .permitAll()
.anyRequest().authenticated())
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return http.build();
}
}
In application.properties:
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://login.microsoftonline.com/{XX}/v2.0
2
Answers
After a lot of research I finally figured out that the request I was doing in the react code did not have the right token. The way it works is you have to first request a login token and then request a "scope" token. I had the login token but not the scope and that's why I kept getting empty granted authorities
This site helped a lot: https://jwt.ms/. When I put the JWT in the token field it showed that there were no scopes (scp).
This is what it should look like (screen shot from https://dev.to/czmiel24/configuring-scopes-in-azure-active-directory-part-1-3bio):
To be very touchy, the "backend" is a resource-server, not a client (client is React app in your case).
I haven’t enough experience with Azure AD to be categoric, but I suspect Microsoft to not follow common OpenID practices (
.well-known/openid-configuration
being accessible from issuer URI and exposingJWKS_URI
) , which results in Spring not resolving authorization public key correctly.Have you tried to set
spring.security.oauth2.resourceserver.jwt.jwk-set-uri
instead or in addition tospring.security.oauth2.resourceserver.jwt.issuer-uri
(issuer-uri
must be set with the exact value found iniss
claim access-token, even trailing slash being important)?