Custom OIDC Provider
Note: This is an advanced feature! We recommend sticking with the supported third-party authentication providers.
Convex can be integrated with any identity provider supporting the OpenID Connect protocol. At minimum this means that the provider can issue ID tokens and exposes the corresponding JWKS. The ID token is passed from the client to your Convex backend which ensures that the token is valid and enables you to query the user information embedded in the token, as described in Auth in Functions.
Server-side integration
Just like with Clerk and Auth0, the backend needs to be aware of the domain of the Issuer and your application's specific applicationID for a given identity provider.
Add these to your convex/auth.config.ts file:
import { AuthConfig } from "convex/server";
export default {
providers: [
{
domain: "https://your.issuer.url.com",
applicationID: "your-application-id",
},
],
} satisfies AuthConfig;
The applicationID property must exactly match the aud field of your JWT and
the domain property must exactly match the iss field of the JWT. Use a tool
like jwt.io to view an JWT and confirm these fields match
exactly.
If multiple providers are provided, the first one fulfilling the above criteria will be used.
If you're not able to obtain tokens with an aud field, you'll need to instead
configure a Custom JWT. If you're not sure if
your token is an OIDC ID token, check
the spec
for a list of all required fields.
OIDC requires the routes ${domain}/.well-known/jwks.json and
${domain}/.well-known/openid-configuration. domain may include a path like
https://your.issuer.url.com/api/auth. This isn't common for third party auth
providers but may be useful if you're implementing OIDC on your own server.
Client-side integration
Integrating a new identity provider
The ConvexProviderWithAuth
component provides a convenient abstraction for building an auth integration
similar to the ones Convex provides for Clerk and
Auth0.
In the following example we build an integration with an imaginary "ProviderX",
whose React integration includes AuthProviderXReactProvider and
useProviderXAuth hook.
First we replace ConvexProvider with AuthProviderXReactProvider wrapping
ConvexProviderWithAuth at the root of our app:
import { AuthProviderXReactProvider } from "providerX";
import { ConvexProviderWithAuth } from "convex/react";
root.render(
<StrictMode>
<AuthProviderXReactProvider>
<ConvexProviderWithAuth client={convex} useAuth={useAuthFromProviderX}>
<App />
</ConvexProviderWithAuth>
</AuthProviderXReactProvider>
</StrictMode>,
);
All we really need is to implement the useAuthFromProviderX hook which gets
passed to the ConvexProviderWithAuth component.
This useAuthFromProviderX hook provides a translation between the auth
provider API and the ConvexReactClient
API, which is ultimately responsible for making sure that the ID token is passed
down to your Convex backend.
function useAuthFromProviderX() {
const { isLoading, isAuthenticated, getToken } = useProviderXAuth();
const fetchAccessToken = useCallback(
async ({ forceRefreshToken }) => {
// Here you can do whatever transformation to get the ID Token
// or null
// Make sure to fetch a new token when `forceRefreshToken` is true
return await getToken({ ignoreCache: forceRefreshToken });
},
// If `getToken` isn't correctly memoized
// remove it from this dependency array
[getToken],
);
return useMemo(
() => ({
// Whether the auth provider is in a loading state
isLoading: isLoading,
// Whether the auth provider has the user signed in
isAuthenticated: isAuthenticated ?? false,
// The async function to fetch the ID token
fetchAccessToken,
}),
[isLoading, isAuthenticated, fetchAccessToken],
);
}
Using the new provider
If you successfully follow the steps above you can now use the standard Convex
utilities for checking the authentication state: the
useConvexAuth() hook and the
Authenticated,
Unauthenticated and
AuthLoading helper components.