/** * Component: OIDC Configuration Step * Documentation: documentation/features/audiobookshelf-integration.md */ 'use client'; import { useState } from 'react'; import { Button } from '@/components/ui/Button'; import { Input } from '@/components/ui/Input'; interface OIDCConfigStepProps { oidcProviderName: string; oidcIssuerUrl: string; oidcClientId: string; oidcClientSecret: string; oidcAccessControlMethod: string; oidcAccessGroupClaim: string; oidcAccessGroupValue: string; oidcAllowedEmails: string; oidcAllowedUsernames: string; oidcAdminClaimEnabled: boolean; oidcAdminClaimName: string; oidcAdminClaimValue: string; oidcTested: boolean; onUpdate: (field: string, value: any) => void; onNext: () => void; onBack: () => void; } export function OIDCConfigStep({ oidcProviderName, oidcIssuerUrl, oidcClientId, oidcClientSecret, oidcAccessControlMethod, oidcAccessGroupClaim, oidcAccessGroupValue, oidcAllowedEmails, oidcAllowedUsernames, oidcAdminClaimEnabled, oidcAdminClaimName, oidcAdminClaimValue, oidcTested, onUpdate, onNext, onBack, }: OIDCConfigStepProps) { const [testing, setTesting] = useState(false); const [testResult, setTestResult] = useState<{ success: boolean; message: string; } | null>( oidcTested ? { success: true, message: 'OIDC configuration verified previously.' } : null ); const testConnection = async () => { setTesting(true); setTestResult(null); try { const response = await fetch('/api/setup/test-oidc', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ issuerUrl: oidcIssuerUrl, clientId: oidcClientId, clientSecret: oidcClientSecret, }), }); const data = await response.json(); if (response.ok && data.success) { setTestResult({ success: true, message: 'OIDC discovery successful! Provider configuration validated.', }); onUpdate('oidcTested', true); } else { setTestResult({ success: false, message: data.error || 'OIDC discovery failed', }); onUpdate('oidcTested', false); } } catch (error) { setTestResult({ success: false, message: error instanceof Error ? error.message : 'Connection test failed', }); onUpdate('oidcTested', false); } finally { setTesting(false); } }; const handleNext = () => { if (!testResult?.success) { setTestResult({ success: false, message: 'Please test the OIDC configuration before proceeding', }); return; } onNext(); }; return (

Configure OIDC Provider

Set up single sign-on authentication with your OIDC provider (Authentik, Keycloak, etc.)

{/* Provider Connection */}

Provider Connection

onUpdate('oidcProviderName', e.target.value)} />

Display name for the login button (e.g., "Authentik", "Keycloak", "SSO")

onUpdate('oidcIssuerUrl', e.target.value)} />

The OIDC issuer URL from your identity provider configuration

onUpdate('oidcClientId', e.target.value)} />

The OAuth2 client ID from your OIDC provider

onUpdate('oidcClientSecret', e.target.value)} />

The OAuth2 client secret from your OIDC provider

{testResult && (
{testResult.success ? ( ) : ( )}

{testResult.success ? 'Success' : 'Error'}

{testResult.message}

)}

Configuration Tips

  • • The redirect URI will be: {typeof window !== 'undefined' ? `${window.location.origin}/api/auth/oidc/callback` : '[Your Domain]/api/auth/oidc/callback'}
  • • Configure this redirect URI in your OIDC provider settings
  • • Required scopes: openid, profile, email, groups
{/* Access Control */}

Access Control

Control who can log in to your application. This is separate from admin permissions.

{oidcAccessControlMethod === 'open' && 'Anyone who can authenticate with your OIDC provider will have access'} {oidcAccessControlMethod === 'group_claim' && 'Only users with a specific group/claim can access'} {oidcAccessControlMethod === 'allowed_list' && 'Only explicitly allowed users can access'} {oidcAccessControlMethod === 'admin_approval' && 'New users must be approved by an admin before access is granted'}

{oidcAccessControlMethod === 'group_claim' && ( <>
onUpdate('oidcAccessGroupClaim', e.target.value)} />

The OIDC claim field that contains group membership (usually "groups" or "roles")

onUpdate('oidcAccessGroupValue', e.target.value)} />

Users must be in this group to access the application

)} {oidcAccessControlMethod === 'allowed_list' && ( <>
onUpdate('oidcAllowedEmails', e.target.value)} />

Enter email addresses separated by commas

onUpdate('oidcAllowedUsernames', e.target.value)} />

Enter usernames separated by commas

)}
{/* Admin Role Mapping */}

Admin Role Mapping

Automatically grant admin permissions based on OIDC claims (e.g., group membership). The first user will always become admin.

onUpdate('oidcAdminClaimEnabled', e.target.checked)} className="mt-1 h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" />

Automatically grant admin role to users with specific OIDC claim values

{oidcAdminClaimEnabled && ( <>
onUpdate('oidcAdminClaimName', e.target.value)} />

The OIDC claim field to check for admin role (usually "groups" or "roles")

onUpdate('oidcAdminClaimValue', e.target.value)} />

Users with this value in their claim will be granted admin role

Example Configuration

In Authentik: Create a group called "readmeabook-admin", add users to it, and set "Admin Claim Value" to "readmeabook-admin"

)}
); }