feat: silent OIDC auth with JWT Bearer tokens for web
Build and Push / release (push) Successful in 3s
Build and Push / build (push) Successful in 3m0s

- Add prompt=none to silently obtain JWT when Authentik session exists
- Flutter sends Bearer token to core-api instead of forward auth cookies
- Fixes cross-subdomain cookie issues between home/api.schweitz.net
- Callback syncs with /auth/sync for user profile and roles
- API interceptor now adds Bearer token on web

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeroen Schweitzer
2026-01-04 16:11:07 +01:00
co-authored by Claude Opus 4.5
parent f0b32ff68b
commit 3fa97bb0b0
6 changed files with 91 additions and 73 deletions
+8 -2
View File
@@ -34,7 +34,12 @@ class OidcServiceWeb implements OidcService {
///
/// Returns a URL that the browser should navigate to for authentication.
/// The [codeVerifier] and [state] are stored for later verification.
Future<String> getAuthorizationUrl() async {
///
/// If [silent] is true, adds `prompt=none` to skip login UI.
/// This is used when the user already has an Authentik session (via NPM).
/// Authentik will instantly redirect back with a code, or return an error
/// if there's no valid session.
Future<String> getAuthorizationUrl({bool silent = false}) async {
// Fetch OIDC discovery document
final discovery = await _fetchDiscovery();
final authEndpoint = discovery['authorization_endpoint'] as String;
@@ -59,10 +64,11 @@ class OidcServiceWeb implements OidcService {
'code_challenge': codeChallenge,
'code_challenge_method': 'S256',
'state': state,
if (silent) 'prompt': 'none', // Silent auth - no UI, instant redirect
};
final uri = Uri.parse(authEndpoint).replace(queryParameters: params);
developer.log('Authorization URL: $uri', name: 'oidc_web');
developer.log('Authorization URL (silent=$silent): $uri', name: 'oidc_web');
return uri.toString();
}