Skip to content

bastman/spring-jwt-playground-2021

Repository files navigation

spring-jwt-playground-2021

let's check how to bearer-auth in 2021 :)

scope

  • 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)

how to run?

profiles

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

swagger:

click "authorize". 
enter "Bearer <your jwt>". 
click "login"

use case: generate self-signed jwt

# 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>"


use case: sign any arbitrary jwt payload

# 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>"

docker

# build image
$ ./gradlew bootBuildImage

# run 
$ docker-compose up

see

multiple jwks algorithms

alternatives - the minimalistic example ...


@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)
       }
   } 

Releases

No releases published

Packages

No packages published

Languages