Thoryn

Quickstarts · spring-boot

Spring Boot 3 — Hub login with Spring Security OAuth2

Add OAuth 2.0 / OIDC to a Spring Boot 3 web app via Spring Security 6's OAuth2 client. Five steps, ~10 lines of YAML.

Tested against:framework: Spring Boot 3.3springSecurity: 6.3

Spring Boot + Thoryn quickstart architecture — your app uses spring-security-oauth2-client with Thoryn as the OIDC provider; Hub federates to your IdP

Prereqs

  • Spring Boot 3.3+ (Java 21 or Kotlin 2.x)
  • A Thoryn account

Step 1 — Register a confidential client in Hub

hub clients create \
  --name "My Spring app" \
  --redirect-uri "http://localhost:8080/login/oauth2/code/thoryn" \
  --grant-types authorization_code,refresh_token \
  --scopes "openid email profile"

Step 2 — Add the dependency

build.gradle.kts:

dependencies {
  implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
  implementation("org.springframework.boot:spring-boot-starter-security")
  implementation("org.springframework.boot:spring-boot-starter-web")
}

Step 3 — Configure

application.yaml:

spring:
  security:
    oauth2:
      client:
        provider:
          thoryn:
            issuer-uri: https://hub.thoryn.org
        registration:
          thoryn:
            provider: thoryn
            client-id: ${THORYN_CLIENT_ID}
            client-secret: ${THORYN_CLIENT_SECRET}
            scope: openid,email,profile
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"

That's it for the framework — Spring Security 6 picks up OIDC discovery from the issuer URI.

Step 4 — Render the user

@RestController
class HomeController {
  @GetMapping("/")
  fun home(@AuthenticationPrincipal principal: OidcUser?): Map<String, Any?> {
    if (principal == null) return mapOf("login" to "/oauth2/authorization/thoryn")
    return mapOf(
      "name" to principal.fullName,
      "email" to principal.email,
      "claims" to principal.claims,
    )
  }
}

Step 5 — Run it

THORYN_CLIENT_ID=... THORYN_CLIENT_SECRET=... ./gradlew bootRun

http://localhost:8080 redirects to /oauth2/authorization/thoryn, lands at Hub, returns to your app with OidcUser populated.

What's next

Troubleshooting

  • InvalidIssuerException: the issuer-uri must match Hub's issuer claim exactly, including trailing slashes (or absence thereof).
  • Refresh tokens missing: add offline_access to the scope list.