feat(auth): OIDC phase 4/5/6 — token refresh, logout revocation, account link
- initMatrix.ts: import the shared Session type; when a session has a refresh token + oidc metadata, wire a LotusOidcTokenRefresher via createClient's refreshToken + tokenRefreshFunction (reactive 401 refresh). Rust crypto is unaffected (still keyed on userId/deviceId). - client/oidcTokenRefresher.ts: OidcTokenRefresher subclass that persists rotated tokens back to the fallback session. - client/oidcLogout.ts + logoutClient: best-effort revoke access+refresh tokens at the issuer's revocation_endpoint on logout (tolerant of failure). - settings/account/OidcManageAccount.tsx: MSC2965 "Manage account" deep-link, shown only when authMetadata is present (OIDC servers); mirrors OtherDevices. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import { discoverAndValidateOIDCIssuerWellKnown } from 'matrix-js-sdk';
|
||||
import { Session } from '../app/state/sessions';
|
||||
|
||||
/**
|
||||
* Best-effort revoke the OIDC access + refresh tokens at the issuer's revocation
|
||||
* endpoint during logout. Tolerant of any failure — logout proceeds regardless
|
||||
* (the local session is cleared by the caller either way).
|
||||
*/
|
||||
export const revokeOidcTokens = async (session: Session): Promise<void> => {
|
||||
if (!session.oidc) return;
|
||||
try {
|
||||
const config = await discoverAndValidateOIDCIssuerWellKnown(session.oidc.issuer);
|
||||
const endpoint = config.revocation_endpoint;
|
||||
if (!endpoint) return;
|
||||
const { clientId } = session.oidc;
|
||||
const revoke = (token: string, hint: string): Promise<Response> =>
|
||||
fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({ token, token_type_hint: hint, client_id: clientId }),
|
||||
});
|
||||
const requests: Promise<Response>[] = [];
|
||||
if (session.refreshToken) requests.push(revoke(session.refreshToken, 'refresh_token'));
|
||||
if (session.accessToken) requests.push(revoke(session.accessToken, 'access_token'));
|
||||
await Promise.allSettled(requests);
|
||||
} catch {
|
||||
/* issuer unreachable / no revocation endpoint — ignore */
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user