Full OIDC logout with id_token_hint for provider session termination
Return the OIDC id_token in the callback response so the frontend can store it and pass it as id_token_hint to the provider's end-session endpoint on logout. This lets Authentik (or any OIDC provider) honor the post_logout_redirect_uri and redirect back to the Cameleer login page instead of showing the provider's own logout page. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,5 +7,7 @@ import jakarta.validation.constraints.NotNull;
|
||||
public record AuthTokenResponse(
|
||||
@NotNull String accessToken,
|
||||
@NotNull String refreshToken,
|
||||
@NotNull String displayName
|
||||
@NotNull String displayName,
|
||||
@Schema(description = "OIDC id_token for end-session logout (only present after OIDC login)")
|
||||
String idToken
|
||||
) {}
|
||||
|
||||
@@ -132,7 +132,7 @@ public class OidcAuthController {
|
||||
|
||||
String displayName = oidcUser.name() != null && !oidcUser.name().isBlank()
|
||||
? oidcUser.name() : oidcUser.email();
|
||||
return ResponseEntity.ok(new AuthTokenResponse(accessToken, refreshToken, displayName));
|
||||
return ResponseEntity.ok(new AuthTokenResponse(accessToken, refreshToken, displayName, oidcUser.idToken()));
|
||||
} catch (ResponseStatusException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -57,7 +57,7 @@ public class OidcTokenExchanger {
|
||||
this.configRepository = configRepository;
|
||||
}
|
||||
|
||||
public record OidcUserInfo(String subject, String email, String name, List<String> roles) {}
|
||||
public record OidcUserInfo(String subject, String email, String name, List<String> roles, String idToken) {}
|
||||
|
||||
/**
|
||||
* Exchanges an authorization code for validated user info.
|
||||
@@ -100,7 +100,7 @@ public class OidcTokenExchanger {
|
||||
List<String> roles = extractRoles(claims, config.rolesClaim());
|
||||
|
||||
log.info("OIDC user authenticated: sub={}, email={}", subject, email);
|
||||
return new OidcUserInfo(subject, email != null ? email : "", name != null ? name : "", roles);
|
||||
return new OidcUserInfo(subject, email != null ? email : "", name != null ? name : "", roles, idTokenStr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,7 +85,7 @@ public class UiAuthController {
|
||||
String refreshToken = jwtService.createRefreshToken(subject, "user", roles);
|
||||
|
||||
log.info("UI user logged in: {}", request.username());
|
||||
return ResponseEntity.ok(new AuthTokenResponse(accessToken, refreshToken, request.username()));
|
||||
return ResponseEntity.ok(new AuthTokenResponse(accessToken, refreshToken, request.username(), null));
|
||||
}
|
||||
|
||||
@PostMapping("/refresh")
|
||||
@@ -108,7 +108,7 @@ public class UiAuthController {
|
||||
String displayName = userRepository.findById(result.subject())
|
||||
.map(UserInfo::displayName)
|
||||
.orElse(result.subject());
|
||||
return ResponseEntity.ok(new AuthTokenResponse(accessToken, refreshToken, displayName));
|
||||
return ResponseEntity.ok(new AuthTokenResponse(accessToken, refreshToken, displayName, null));
|
||||
} catch (ResponseStatusException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
|
||||
Reference in New Issue
Block a user