import { useCallback, useEffect, useState } from 'react'
import { Loading, ErrorState } from '../../../components/PageState.jsx'
import ProviderIcon from '../../../components/ProviderIcon.jsx'
import RecoveryCodesDisplay from '../../../components/security/RecoveryCodesDisplay.jsx'
import TrustedDevicesPanel from '../../../components/security/TrustedDevicesPanel.jsx'
import RecoveryCodesPanel from '../../../components/security/RecoveryCodesPanel.jsx'
import EmailAddressPanel from '../../../components/security/EmailAddressPanel.jsx'
import { IdentitySummary, linkBanner, linkableProviders, unlinkPrompt } from '../../../components/security/linkedIdentities.jsx'
import { api } from '../../../api/client.js'
// Link/unlink external SSO identities to this account. Linking redirects through
// the provider's OAuth flow (/auth/sso/:id/link) and returns here with ?linked
// or ?link_error. Only providers that are enabled + valid can be linked.
function LinkedAccounts() {
const [linked, setLinked] = useState(null)
const [available, setAvailable] = useState([])
const [error, setError] = useState('')
const banner = linkBanner(window.location.search)
const load = useCallback(async () => {
try {
const [ids, avail] = await Promise.all([
api.myIdentities(),
api.authProviders().catch(() => []),
])
setLinked(ids)
setAvailable(Array.isArray(avail) ? avail : [])
} catch {
setError('Could not load linked accounts.')
}
}, [])
useEffect(() => {
load()
}, [load])
const nameFor = (id) => available.find((p) => p.id === id)?.name || id.charAt(0).toUpperCase() + id.slice(1)
async function unlink(identity) {
if (!window.confirm(unlinkPrompt(identity, nameFor(identity.provider)))) return
try {
await api.unlinkIdentity(identity.provider, identity.id)
await load()
} catch (err) {
setError(err.message || 'Could not unlink.')
}
}
if (error) return
Link a Google, Discord, Steam, or other SSO account so you can sign in with it. SSO can only sign in to an account it is linked to — linking here is what grants that access.
{banner && ({banner.text}
)} {linked.length > 0 && (No SSO providers are enabled. Configure them under Authentication.
)}Add a time-based one-time code (TOTP) from an authenticator app as a second step at login. Optional, and only affects your own account.
1. Scan this QR code with your authenticator app, then enter the current 6-digit code to confirm.
Enter a current code from your authenticator to turn two-factor off.
{msg}
} {error &&{error}
} {/* One-time recovery codes shown right after enabling 2FA. */} {newCodes && (