feat: hardcode Logto org scopes in auth flow, hide from admin UI
Always include urn:logto:scope:organizations and urn:logto:scope:organization_roles in OIDC auth requests. These are required for role mapping in multi-tenant setups and harmless for non-Logto providers (unknown scopes ignored per OIDC spec). Filter them from the OIDC admin config page so they don't confuse standalone server admins or SaaS tenants. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,10 @@ interface OidcInfo {
|
||||
additionalScopes?: string[];
|
||||
}
|
||||
|
||||
// Logto org scopes required for role mapping in multi-tenant setups.
|
||||
// Always requested, harmless for non-Logto providers (unknown scopes are ignored per OIDC spec).
|
||||
const PLATFORM_SCOPES = ['urn:logto:scope:organizations', 'urn:logto:scope:organization_roles'];
|
||||
|
||||
const SUBTITLES = [
|
||||
"Prove you're not a mirage",
|
||||
"Only authorized cameleers beyond this dune",
|
||||
@@ -76,7 +80,7 @@ export function LoginPage() {
|
||||
if (oidc && !forceLocal && !autoRedirected.current) {
|
||||
autoRedirected.current = true;
|
||||
const redirectUri = `${window.location.origin}${config.basePath}oidc/callback`;
|
||||
const scopes = ['openid', 'email', 'profile', ...(oidc.additionalScopes || [])];
|
||||
const scopes = ['openid', 'email', 'profile', ...PLATFORM_SCOPES, ...(oidc.additionalScopes || [])];
|
||||
const params = new URLSearchParams({
|
||||
response_type: 'code',
|
||||
client_id: oidc.clientId,
|
||||
@@ -100,7 +104,7 @@ export function LoginPage() {
|
||||
if (!oidc) return;
|
||||
setOidcLoading(true);
|
||||
const redirectUri = `${window.location.origin}${config.basePath}oidc/callback`;
|
||||
const scopes = ['openid', 'email', 'profile', ...(oidc.additionalScopes || [])];
|
||||
const scopes = ['openid', 'email', 'profile', ...PLATFORM_SCOPES, ...(oidc.additionalScopes || [])];
|
||||
const params = new URLSearchParams({
|
||||
response_type: 'code',
|
||||
client_id: oidc.clientId,
|
||||
|
||||
@@ -31,7 +31,8 @@ export function OidcCallback() {
|
||||
api.GET('/auth/oidc/config').then(({ data }) => {
|
||||
if (data?.authorizationEndpoint && data?.clientId) {
|
||||
const redirectUri = `${window.location.origin}${config.basePath}oidc/callback`;
|
||||
const scopes = ['openid', 'email', 'profile', ...(data.additionalScopes || [])];
|
||||
const PLATFORM_SCOPES = ['urn:logto:scope:organizations', 'urn:logto:scope:organization_roles'];
|
||||
const scopes = ['openid', 'email', 'profile', ...PLATFORM_SCOPES, ...(data.additionalScopes || [])];
|
||||
const p = new URLSearchParams({
|
||||
response_type: 'code',
|
||||
client_id: data.clientId,
|
||||
|
||||
@@ -23,6 +23,9 @@ interface OidcFormData {
|
||||
additionalScopes: string[];
|
||||
}
|
||||
|
||||
// Platform-managed scopes — always requested by the auth flow, hidden from the admin UI
|
||||
const PLATFORM_SCOPES = new Set(['urn:logto:scope:organizations', 'urn:logto:scope:organization_roles']);
|
||||
|
||||
const EMPTY_CONFIG: OidcFormData = {
|
||||
enabled: false,
|
||||
autoSignup: true,
|
||||
@@ -61,7 +64,7 @@ export default function OidcConfigPage() {
|
||||
userIdClaim: data.userIdClaim ?? 'sub',
|
||||
defaultRoles: data.defaultRoles ?? ['VIEWER'],
|
||||
audience: (data as any).audience ?? '',
|
||||
additionalScopes: (data as any).additionalScopes ?? [],
|
||||
additionalScopes: ((data as any).additionalScopes ?? []).filter((s: string) => !PLATFORM_SCOPES.has(s)),
|
||||
}))
|
||||
.catch(() => setForm(EMPTY_CONFIG));
|
||||
}, []);
|
||||
|
||||
Reference in New Issue
Block a user