This demo shows how to build a Spring Boot app and secure it with OAuth 2.0. Then, it shows how to create resource servers with Quarkus and Micronaut.
Prerequisites:
Use start.spring.io to create a new Spring Boot project with OAuth dependencies.
https start.spring.io/starter.tgz \
dependencies==web,oauth2-client,oauth2-resource-server \
baseDir==spring-boot \
| tar -xzvf - && cd spring-boot
-
Ensure it starts and you can log in as
user
../gradlew bootRun
-
Add your Auth0 domain to
application.properties
to configure a resource server.spring.security.oauth2.resourceserver.jwt.issuer-uri=https://<your-auth0-domain>/
-
Add a
HelloController.java
file with the following code.@RestController class HelloController { @GetMapping("/hello") public String hello(Principal principal) { return "Hello, " + principal.getName() + "!"; } }
-
Run the app using Gradle.
./gradlew bootRun
-
Open a new terminal and use HTTPie to test the resource server.
http :8080/hello
You will get a 401 response.
-
Create an access token using Auth0’s CLI:
auth0 test token -a https://<your-auth0-domain>/api/v2/
-
Set the access token as an environment variable:
TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6...
-
Access your resource server using HTTPie:
http :8080/hello "Authorization: Bearer $TOKEN"
-
You should receive a 200 response with a message.
Hello, auth0|61bcbc76f64d4a0072af8a1d!
-
Stop the resource server using Ctrl+C.
-
Create a
SecurityConfiguration.java
file that contains the same defaults as Spring Security.@Configuration public class SecurityConfiguration { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(authz -> authz.anyRequest().authenticated()); http.oauth2ResourceServer().jwt(); return http.build(); } }
-
Confirm you can still access the
/hello
endpoint.http :8080/hello "Authorization: Bearer $TOKEN"
-
Modify the
SecurityFilterChain
bean to enable OIDC authentication.@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { ... http.oauth2Login(); ... }
-
Create an OIDC application using the Auth0 CLI.
auth0 apps create --reveal-secrets
-
Name:
Spring Boot
-
Type: Regular Web Application
-
Allowed Callback URLs:
http://localhost:8080/login/oauth2/code/auth0
-
Allowed Logout URLs:
http://localhost:8080
-
-
Update
application.properties
to include these values, removing any previous properties.spring.security.oauth2.client.provider.auth0.issuer-uri=https://<your-auth0-domain>/ spring.security.oauth2.client.registration.auth0.client-id=<client-id> spring.security.oauth2.client.registration.auth0.client-secret=<client-secret> spring.security.oauth2.client.registration.auth0.scope=openid,profile,email auth0.audience=https://<your-auth0-domain>/api/v2/
-
If you start your app, it’ll fail with the following error:
Method filterChain in com.example.demo.SecurityConfiguration required a bean of type 'org.springframework.security.oauth2.jwt.JwtDecoder' that could not be found.
-
Add a JWT decoder bean that does audience validation.
@Value("${auth0.audience}") private String audience; @Value("${spring.security.oauth2.client.provider.auth0.issuer-uri}") private String issuer; @Bean JwtDecoder jwtDecoder() { NimbusJwtDecoder jwtDecoder = JwtDecoders.fromOidcIssuerLocation(issuer); OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience); OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer); OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator); jwtDecoder.setJwtValidator(withAudience); return jwtDecoder; }
-
Create an
AudienceValidator
class to validate JWTs.class AudienceValidator implements OAuth2TokenValidator<Jwt> { private final String audience; AudienceValidator(String audience) { this.audience = audience; } public OAuth2TokenValidatorResult validate(Jwt jwt) { OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null); if (jwt.getAudience().contains(audience)) { return OAuth2TokenValidatorResult.success(); } return OAuth2TokenValidatorResult.failure(error); } }
-
Add a
HomeController
to display the user’s name after they log in.@RestController class HomeController { @GetMapping("/") public String home(@AuthenticationPrincipal OidcUser user) { return "Hello, " + user.getFullName() + "!"; } }
-
Restart the server. Use Ctrl+C to stop it if it’s running.
./gradlew bootRun
-
Log in at
http://localhost:8080
. -
Use HTTPie again to confirm your resource server still works.
http :8080/hello "Authorization: Bearer $TOKEN"
-
You can inspect your access token at jwt.io.
-
Clone the Okta Quarkus Sample:
git clone https://github.com/okta-samples/okta-quarkus-sample.git quarkus
-
Update
application.properties
to update the public key location. Remove all other properties.quarkus.oidc.auth-server-url=https://<your-auth0-domain> mp.jwt.verify.publickey.location=${quarkus.oidc.auth-server-url}/.well-known/jwks.json mp.jwt.verify.issuer=${quarkus.oidc.auth-server-url}
-
Run the app:
mvn quarkus:dev
-
Verify you can access it with an access token.
http :8080/hello "Authorization: Bearer $TOKEN"
-
Clone the Okta Micronaut Sample:
git clone https://github.com/okta-samples/okta-micronaut-sample.git micronaut
-
Update
application.yml
to change the public key location. Remove all other properties.micronaut.security.token.jwt.enabled: true micronaut.security.token.jwt.signatures.jwks.auth0.url: https://<your-auth0-domain>/.well-known/jwks.json
-
Run the app:
mvn mn:run
-
Verify you can access it with an access token.
http :8080/hello "Authorization: Bearer $TOKEN"