let's check how to bearer-auth in 2021 :)
- single-tenant resource-server
- bearer auth: validate jwt claims: exp, iss, aud
- basic auth
- simple fake authorization server:
- why? ... to simplify local development
- generate self-signed jwt
- sign any arbitrary jwt payload using (RS256, HS256)
- spring boot (mvc)
- auth-basicauth: enable basic auth. see: app/src/main/resources/application-auth-basicauth.yml
- auth-jwt-default: enable bearer auth. requires issuer-uri + audience as env variables see: app/src/main/resources/application-auth-jwt-default.yml
- auth-jwt-fakeHS256: enable bearer auth. accepts/generates self-signed jwt (HS256). Do not use in production! see: app/src/main/resources/application-auth-jwt-fakeHS256.yml
- auth-jwt-fakeRS256: enable bearer auth. accepts/generates self-signed jwt (RS256). Do not use in production! see: app/src/main/resources/application-auth-jwt-fakeRS256.yml
VM Options, e.g.:
-D.spring.profiles.active=auth-basicauth
-D.spring.profiles.active=auth-jwt-default
-D.spring.profiles.active=auth-jwt-fakeHS256
-D.spring.profiles.active=auth-jwt-fakeRS256
Note: you can combine jwt auth and basic auth to support graceful migration from basic auth to bearer auth e.g.:
-D.spring.profiles.active=auth-basicauth,auth-jwt-fakeHS256
click "authorize".
enter "Bearer <your jwt>".
click "login"
# requires profile: auth-fakeRS256 (or auth-fakeHS256)
$ curl -v -X POST "http://localhost:8080/oauth/example-token"
--> returns a self-signed jwt
$ curl -X GET "http://localhost:8080/api/me" -H "Authorization: Bearer <your token>"
# requires profile: auth-fakeRS256 (or auth-fakeHS256)
# payload to sign ...
{
"https://example.com/claims/userid": "my-issuer-1|my-user-id-1",
"https://app.example.com/roles": [
"my-role-1",
"my-role-2"
],
"https://example.com/claims/given_name": "my-given-name",
"https://example.com/claims/family_name": "my-family-name",
"https://example.com/claims/email": "[email protected]",
"iss": "https://my-issuer-1.local",
"sub": "my-issuer-1|my-user-id-1",
"aud": [
"my-audience-1",
"my-audience-2"
],
"iat": 1604327123,
"exp": 1604377523,
"scope": "openid profile email"
}
$ curl -v -X POST "http://localhost:8080/oauth/sign-token" -H "Content-Type: application/json" -d "{ \"https://example.com/claims/userid\": \"my-issuer-1|my-user-id-1\", \"https://app.example.com/roles\": [ \"my-role-1\", \"my-role-2\" ], \"https://example.com/claims/given_name\": \"my-given-name\", \"https://example.com/claims/family_name\": \"my-family-name\", \"https://example.com/claims/email\": \"[email protected]\", \"iss\": \"https://my-issuer-1.local\", \"sub\": \"my-issuer-1|my-user-id-1\", \"aud\": [ \"my-audience-1\", \"my-audience-2\" ], \"iat\": 1604327123, \"exp\": 1604377523, \"scope\": \"openid profile email\"}"
--> returns a self-signed jwt
$ curl -X GET "http://localhost:8080/api/me" -H "Authorization: Bearer <your token>"
# build image
$ ./gradlew bootBuildImage
# run
$ docker-compose up
- https://itnext.io/secures-rest-apis-with-spring-security-5-and-auth0-41d579ca1e27
- https://github.com/spring-projects/spring-security/blob/main/docs/manual/src/docs/asciidoc/_includes/servlet/oauth2/oauth2-resourceserver.adoc
- https://github.com/hantsy/spring-security-auth0-sample/tree/master/api
- https://github.com/hantsy/spring-security-auth0-sample/blob/master/docs/api.md
- https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2resourceserver
- https://connect2id.com/products/nimbus-jose-jwt/examples/validating-jwt-access-tokens
- https://connect2id.com/products/nimbus-jose-jwt/examples/jwt-with-hmac
- https://bitbucket.org/connect2id/nimbus-jose-jwt/src/master/
- https://github.com/spring-projects-experimental/spring-authorization-server
-
https://github.com/sdoxsee/examples/tree/master/multi-tenant-jwt-resourceserver
-
https://bitbucket.org/connect2id/nimbus-jose-jwt/issues/353/support-jwks-with-multiple-algorithms
-
https://bitbucket.org/connect2id/nimbus-jose-jwt/pull-requests/65
-
https://www.novatec-gmbh.de/en/blog/how-to-support-different-jwts-in-your-spring-boot-application/
@Bean
fun springWebFilterChain(http: HttpSecurity): SecurityFilterChain {
return http
.httpBasic { it.disable() }
.csrf { it.disable() }
.sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }
.authorizeRequests {
it
.antMatchers(*(endpointsUnsecured.toTypedArray())).permitAll()
.antMatchers(*(endpointsFullyAuthenticated.toTypedArray())).fullyAuthenticated()
.anyRequest().authenticated()
}
.oauth2ResourceServer { superSimpleResourceServer(it) }
.build()
}
private fun superSimpleResourceServer(rs: OAuth2ResourceServerConfigurer<HttpSecurity?>) {
val issuer = "https://my-issuer.example.com/"
val validator:OAuth2TokenValidator<Jwt> = JwtValidators.createDefaultWithIssuer(issuer)
// note: does not validate audience
val decoder:NimbusJwtDecoder = JwtDecoders.fromIssuerLocation(issuer) as NimbusJwtDecoder
decoder.setJwtValidator(validator)
rs.jwt {
it.decoder(decoder)
}
}