feat(auth): OIDC phase 2 — login initiation (discover/register/authorize)
- oidc/oidcState.ts (pure, +3 tests): dynamic-registration cache (by issuer + redirectUri, corrupt-tolerant) and parseOidcCallbackParams (success/error/invalid). - oidc/oidcLoginUtil.ts: getOrRegisterClientId (cache + registerOidcClient) and startOidcLogin (discoverAndValidateOIDCIssuerWellKnown -> generateOidcAuthorization Url -> redirect; invalidates the cache on failure). redirectUri is the deterministic getOidcCallbackUrl(), and the SDK returns clientId/issuer on callback, so no hand-rolled transient state is needed. - login/OidcLogin.tsx: native-OIDC button mirroring SSOLogin + TokenLogin async/error. - login/Login.tsx: issuer-gated — when discovery advertises an issuer, render OidcLogin and suppress password/legacy-SSO; non-OIDC servers unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,9 @@ import { useParsedLoginFlows } from '../../../hooks/useParsedLoginFlows';
|
||||
import { PasswordLoginForm } from './PasswordLoginForm';
|
||||
import { SSOLogin } from '../SSOLogin';
|
||||
import { TokenLogin } from './TokenLogin';
|
||||
import { OidcLogin } from './OidcLogin';
|
||||
import { useAutoDiscoveryInfo } from '../../../hooks/useAutoDiscoveryInfo';
|
||||
import { getOidcIssuer } from '../../../cs-api';
|
||||
import { OrDivider } from '../OrDivider';
|
||||
import { getLoginPath, getRegisterPath, withSearchParam } from '../../pathUtils';
|
||||
import { usePathWithOrigin } from '../../../hooks/usePathWithOrigin';
|
||||
@@ -36,6 +39,7 @@ const useLoginSearchParams = (searchParams: URLSearchParams): LoginPathSearchPar
|
||||
|
||||
export function Login() {
|
||||
const server = useAuthServer();
|
||||
const discovery = useAutoDiscoveryInfo();
|
||||
const { hashRouter } = useClientConfig();
|
||||
const { loginFlows } = useAuthFlows();
|
||||
const [searchParams] = useSearchParams();
|
||||
@@ -54,6 +58,29 @@ export function Login() {
|
||||
|
||||
const parsedFlows = useParsedLoginFlows(loginFlows.flows);
|
||||
|
||||
// Next-gen auth (MSC3861/MSC2965): when the server advertises an OIDC issuer in
|
||||
// its `.well-known` discovery, use the native OIDC flow and suppress the
|
||||
// password / legacy-SSO forms (those servers, e.g. MAS, reject `m.login.password`).
|
||||
const oidc = getOidcIssuer(discovery);
|
||||
if (oidc.issuer) {
|
||||
return (
|
||||
<Box direction="Column" gap="500">
|
||||
<Text as="h1" size="H2" priority="400">
|
||||
Login
|
||||
</Text>
|
||||
<OidcLogin
|
||||
issuer={oidc.issuer}
|
||||
homeserverBaseUrl={discovery['m.homeserver'].base_url}
|
||||
serverName={server}
|
||||
/>
|
||||
<span data-spacing-node />
|
||||
<Text align="Center">
|
||||
Do not have an account? <Link to={getRegisterPath(server)}>Register</Link>
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box direction="Column" gap="500">
|
||||
<Text as="h1" size="H2" priority="400">
|
||||
|
||||
Reference in New Issue
Block a user