Use this file to discover all available pages before exploring further.
Some Matrix homeservers delegate authentication to an external OpenID Connect (OIDC) provider rather than handling credentials directly. The matrix-js-sdk provides first-class support for this via the Authorization Code flow with PKCE.
OIDC support in the SDK is currently marked as experimental. APIs may change between minor releases.
Fetch and validate the issuer’s OpenID configuration using discoverAndValidateOIDCIssuerWellKnown(). The issuer URL comes from the homeserver’s /auth_issuer endpoint (or its .well-known/matrix/client document).
import { discoverAndValidateOIDCIssuerWellKnown } from "matrix-js-sdk/lib/oidc";// issuer is the value from GET /_matrix/client/unstable/org.matrix.msc2965/auth_issuerconst oidcConfig = await discoverAndValidateOIDCIssuerWellKnown(issuer);// oidcConfig is an OidcClientConfig — validated metadata plus signing keys.console.log("Authorization endpoint:", oidcConfig.authorization_endpoint);console.log("Token endpoint:", oidcConfig.token_endpoint);
This fetches https://<issuer>/.well-known/openid-configuration, validates it against the Matrix OIDC requirements, and also retrieves the issuer’s signing keys from the jwks_uri.
This function is deprecated in favour of MatrixClient.getAuthMetadata() for clients that already have a MatrixClient instance. Use discoverAndValidateOIDCIssuerWellKnown() when you need to validate the issuer before a client exists.
If your app does not have a pre-registered client_id, use registerOidcClient() to perform Dynamic Client Registration (MSC2966):
import { registerOidcClient, type OidcRegistrationClientMetadata } from "matrix-js-sdk/lib/oidc";const clientMetadata: OidcRegistrationClientMetadata = { clientName: "My Matrix App", clientUri: "https://my-app.example.com", logoUri: "https://my-app.example.com/logo.png", applicationType: "web", redirectUris: ["https://my-app.example.com/oidc/callback"], contacts: ["support@my-app.example.com"], tosUri: "https://my-app.example.com/terms", policyUri: "https://my-app.example.com/privacy",};const clientId = await registerOidcClient(oidcConfig, clientMetadata);// Store clientId persistently — re-register only if necessary.
registerOidcClient() will throw if:
The issuer does not expose a registration_endpoint.
The issuer does not support the authorization_code or refresh_token grant types.
The registration request fails or returns an invalid response.
Persist the returned clientId in your application’s storage. Re-registration creates a new client entry on the issuer and should be avoided on every app load.
Build the URL to redirect the user to for login. Use generateOidcAuthorizationUrl(), which creates a PKCE-protected authorization request and stores the required state in sessionStorage:
import { generateOidcAuthorizationUrl } from "matrix-js-sdk/lib/oidc";import { secureRandomString } from "matrix-js-sdk/lib/randomstring";const nonce = secureRandomString(8);const authorizationUrl = await generateOidcAuthorizationUrl({ metadata: oidcConfig, clientId, homeserverUrl: "https://matrix.org", redirectUri: "https://my-app.example.com/oidc/callback", nonce, // Optionally set prompt to control the OP's UI: // "login" forces re-authentication, "create" opens the registration flow. prompt: "login",});// Redirect the user's browser to authorizationUrlwindow.location.href = authorizationUrl;
The generated URL includes:
response_type=code and response_mode=query
A PKCE code_challenge (S256 method)
An opaque state value that maps back to the stored session state
A scope covering openid plus the Matrix device API
Step 4 — Handle the callback and exchange the code
After the user authenticates, the OIDC provider redirects to your redirectUri with code and state query parameters. Exchange these for tokens:
import { completeAuthorizationCodeGrant } from "matrix-js-sdk/lib/oidc";// Parse `code` and `state` from the callback URL query stringconst params = new URLSearchParams(window.location.search);const code = params.get("code")!;const state = params.get("state")!;const { oidcClientSettings, tokenResponse, homeserverUrl, identityServerUrl, idTokenClaims,} = await completeAuthorizationCodeGrant(code, state);// tokenResponse contains access_token, refresh_token, expires_at, etc.// oidcClientSettings.clientId and .issuer are needed for token refresh// idTokenClaims contains the user's identity claims
completeAuthorizationCodeGrant() reads the stored state from sessionStorage, validates the id token, and returns the full token response along with the homeserver URL that was embedded in the state at the start of the flow.
generateOidcAuthorizationUrl() and completeAuthorizationCodeGrant() use window.sessionStorage to store PKCE state and rely on window.location. They require a secure context (https://) for PKCE code challenge generation.
Node.js
These browser-specific functions are not suitable for use in Node.js. For CLI or server-side OAuth flows, implement the authorization code exchange manually using generateAuthorizationParams() and generateAuthorizationUrl(), storing state in your own mechanism.
OIDC errors are surfaced as Error instances with a message matching one of the OidcError enum values:
import { OidcError } from "matrix-js-sdk/lib/oidc";try { const clientId = await registerOidcClient(oidcConfig, clientMetadata);} catch (err) { if ((err as Error).message === OidcError.DynamicRegistrationNotSupported) { // The issuer doesn't support dynamic registration. // Use a pre-registered client_id instead. } else if ((err as Error).message === OidcError.DynamicRegistrationFailed) { console.error("Registration request failed"); }}try { const result = await completeAuthorizationCodeGrant(code, state);} catch (err) { if ((err as Error).message === OidcError.MissingOrInvalidStoredState) { // The stored PKCE state could not be found — the user may have // navigated to the callback URL directly, or sessionStorage was cleared. } else if ((err as Error).message === OidcError.CodeExchangeFailed) { console.error("Token exchange failed"); }}