bumpy-controller-43157
05/13/2025, 10:21 AMbrief-egg-61061
05/13/2025, 10:21 AMbrief-egg-61061
05/13/2025, 10:21 AMX-API-Key
) with a secret value in the request to your webhook endpoint. Your endpoint should check for this header and validate its value before processing the request. kotlin import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* @SpringBootApplication class Oauth2WebhookApplication fun main(args: Array<String>) { runApplication<Oauth2WebhookApplication>(*args) } @RestController @RequestMapping("/token-hook") class WebhookController { private val expectedApiKey = "MY API KEY" // Replace with your actual API key @PostMapping fun handleTokenHook( @RequestHeader("X-API-Key") apiKey: String?, @RequestBody payload: Map<String, Any> ): ResponseEntity<Any> { if (apiKey != expectedApiKey) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid API Key") } // Process the payload as needed println("Received payload: $payload") // Optionally, modify the response as required by Ory's webhook contract return ResponseEntity.ok(mapOf("session" to mapOf("id_token" to mapOf("custom_claim" to "value")))) } }
Notes: - The endpoint /token-hook
expects a POST request with a JSON body. - The header X-API-Key
is checked for authentication, as described in the Ory documentation for header-based API key authentication. - Replace "MY API KEY"
with your actual secret. - The response structure can be adjusted to fit your needs and Ory’s webhook contract. For more details on configuring Ory to use header authentication for webhooks, see the official documentation: [Customizing claims with OAuth2 webhooks](https://www.ory.sh/docs/hydra/guides/claims-at-refresh/) and [Request authentication](https://www.ory.sh/docs/guides/integrate-with-ory-cloud-through-webhooks/#request-authentication).bumpy-controller-43157
05/13/2025, 10:24 AMbrief-egg-61061
05/13/2025, 10:24 AMbrief-egg-61061
05/13/2025, 10:24 AMX-API-Key
) with a configured value in incoming requests to your webhook endpoint. The documentation does not provide a Spring Security-specific implementation, but it does show the expected authentication mechanism and header usage for webhooks in Ory [Customizing claims with OAuth2 webhooks](https://www.ory.sh/docs/hydra/guides/claims-at-refresh/) and [Request authentication](https://www.ory.sh/docs/guides/integrate-with-ory-cloud-through-webhooks/#request-authentication). To apply this in Spring Security, you would configure a filter that checks the presence and value of the X-API-Key
header before allowing access to the webhook endpoint. Here is a minimal example, directly reflecting the Ory approach: kotlin import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter import org.springframework.stereotype.Component import org.springframework.web.filter.OncePerRequestFilter import javax.servlet.FilterChain import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse @Configuration class SecurityConfig { @Bean fun filterChain(http: HttpSecurity, apiKeyAuthFilter: ApiKeyAuthFilter): SecurityFilterChain { http .csrf().disable() .authorizeRequests() .antMatchers("/token-hook").authenticated() .anyRequest().permitAll() .and() .addFilterBefore(apiKeyAuthFilter, AbstractPreAuthenticatedProcessingFilter::class.java) return http.build() } } @Component class ApiKeyAuthFilter : OncePerRequestFilter() { private val expectedApiKey = "MY API KEY" // Replace with your actual API key override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain ) { if (request.requestURI == "/token-hook") { val apiKey = request.getHeader("X-API-Key") if (apiKey != expectedApiKey) { response.status = HttpServletResponse.SC_UNAUTHORIZED response.writer.write("Invalid API Key") return } } filterChain.doFilter(request, response) } }
Key points: - The filter checks the X-API-Key
header for requests to /token-hook
. - If the header is missing or incorrect, the request is rejected with a 401 Unauthorized. - This matches the Ory documentation for header-based API key authentication for webhooks. For more details on the expected authentication mechanism, see [Ory's webhook authentication documentation](https://www.ory.sh/docs/guides/integrate-with-ory-cloud-through-webhooks/#request-authentication). If you need a more advanced or production-ready solution, you may want to use a custom authentication provider or entry point, but the above is a direct and minimal implementation as per the Ory documentation.bumpy-controller-43157
05/13/2025, 12:04 PMbrief-egg-61061
05/13/2025, 12:04 PMbrief-egg-61061
05/13/2025, 12:04 PMsession
, request
, and within those, you can find the client_id
, granted_scopes
, and, for authorization code flows, the subject (user id) and possibly the email if included in the session claims. The payload is a JSON object, and you may receive additional or missing properties depending on the flow and Ory configuration. To ensure Jackson does not fail on unknown or missing properties, you should use the @JsonIgnoreProperties(ignoreUnknown = true)
annotation on your data classes. Here’s how you can define the relevant Kotlin data classes and configure Jackson accordingly: kotlin import com.fasterxml.jackson.annotation.JsonIgnoreProperties @JsonIgnoreProperties(ignoreUnknown = true) data class TokenHookRequest( val session: Session? = null, val request: OAuthRequest? = null ) @JsonIgnoreProperties(ignoreUnknown = true) data class Session( val id_token: IdToken? = null ) @JsonIgnoreProperties(ignoreUnknown = true) data class IdToken( val subject: String? = null, // user id val id_token_claims: IdTokenClaims? = null ) @JsonIgnoreProperties(ignoreUnknown = true) data class IdTokenClaims( val email: String? = null ) @JsonIgnoreProperties(ignoreUnknown = true) data class OAuthRequest( val client_id: String? = null, val granted_scopes: List<String>? = null )
Usage in Controller: kotlin @PostMapping fun handleTokenHook( @RequestHeader("X-API-Key") apiKey: String?, @RequestBody payload: TokenHookRequest ): ResponseEntity<Any> { val userId = payload.session?.id_token?.subject val email = payload.session?.id_token?.id_token_claims?.email val clientId = payload.request?.client_id val scopes = payload.request?.granted_scopes // Your logic here return ResponseEntity.ok().build() }
Jackson Configuration: By default, Spring Boot configures Jackson to use these annotations. No further configuration is needed if you use @JsonIgnoreProperties(ignoreUnknown = true)
on your data classes. Reference: The structure of the webhook payload and the relevant fields are described in the Ory documentation: [Customizing claims with OAuth2 webhooks](https://www.ory.sh/docs/hydra/guides/claims-at-refresh/)