I'm trying to implement a proof of concept project taken from this video. The idea is to have 2 small spring boot applications:
- Client application where users are able to authenticate by Google or Okta.
- Resource server application where we have some endpoints secured and verify authorization again in Google or Okta.
The problem is that in the case of Okta everything works fine. User can authenticate and then access endpoints on the resource server.
But in the case of Google, user authentication is successful, but when I want to access the resource server's endpoints I see exception on the resource server side:
org.springframework.security.oauth2.core.OAuth2AuthenticationException: An error occurred while attempting to decode the Jwt: Invalid token
at org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider.authenticate(JwtAuthenticationProvider.java:92) ~[spring-security-oauth2-resource-server-5.2.1.RELEASE.jar:5.2.1.RELEASE]
...
Caused by: org.springframework.security.oauth2.jwt.JwtException: An error occurred while attempting to decode the Jwt: Invalid unsecured/JWS/JWE header: Invalid JSON: Unexpected token ɭ� at position 2.
Client application
application.yml
security:
oauth2:
client:
registration:
google:
client-id: <client-id>
client-secret: <client-secret>
okta:
client-id: 0oa2p1e8o4z4Q9bJx5d7
client-secret: eTTbGN3yD7zlBoY6G_ea449pw34TLr53QkOIQTUy
provider:
okta:
issuer-uri: https://<okta-dev-id>.okta.com/oauth2/default
SsecOidcApplication.class (Client main class)
@SpringBootApplication
public class SsecOidcApplication {
@Bean
WebClient client(ClientRegistrationRepository regRepo,
OAuth2AuthorizedClientRepository cliRepo) {
ServletOAuth2AuthorizedClientExchangeFilterFunction fFunc =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(
regRepo,
cliRepo
);
fFunc.setDefaultOAuth2AuthorizedClient(true);
return WebClient.builder()
.baseUrl("http://localhost:8081/resources")
.apply(fFunc.oauth2Configuration())
.build();
}
public static void main(String[] args) {
SpringApplication.run(SsecOidcApplication.class, args);
}
}
@RestController
class OidcController {
private final WebClient client;
public OidcController(WebClient client) {
this.client = client;
}
@GetMapping("/")
String hello() {
return "Bonjour Montreal!";
}
@GetMapping("/something")
String getSomethingFromRServer() {
return client.get()
.uri("/something")
.retrieve()
.bodyToMono(String.class)
.block();
}
@GetMapping("/claims")
Map getClaimsFromRServer() {
return client.get()
.uri("/claims")
.retrieve()
.bodyToMono(Map.class)
.block();
}
@GetMapping("/email")
String getSubjectFromRServer() {
return client.get()
.uri("/email")
.retrieve()
.bodyToMono(String.class)
.block();
}
}
Resource server app
application.yml
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://accounts.google.com # for okta replace I replace it with https://<okta-dev-id>.okta.com/oauth2/default
SsecResSvrApplication (Resource server main class)
@SpringBootApplication
public class SsecResSvrApplication {
public static void main(String[] args) {
SpringApplication.run(SsecResSvrApplication.class, args);
}
}
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.mvcMatchers("/resources/claims/**").hasAuthority("SCOPE_openid")
.mvcMatchers("/resources/email/**").hasAuthority("SCOPE_email")
.and().oauth2ResourceServer().jwt();
}
}
@RestController
@RequestMapping("/resources")
class ResourceController {
@GetMapping("/something")
String getSomething() {
return "This is really something!";
}
@GetMapping("/claims")
Map<String, Object> getClaims(@AuthenticationPrincipal Jwt jwt) {
return jwt.getClaims();
}
@GetMapping("/email")
String getSubject(@AuthenticationPrincipal Jwt jwt) {
return jwt.getSubject();
}
}
I'm new to Spring Security and OAuth, can anyone help with this? To test this I'm changing only resourceserver: jwt: issuer-uri: Do I need to do some special setup for Google? The error on client side is pretty straightforward:
401 Unauthorized from GET http://localhost:8081/resources/something