Repository navigation
Allow oidc.providers to be resolved at runtime, like callbackUrl #48
Description
Is there an existing issue that is already proposing this?
- I have searched the existing issues
Is your feature request related to a problem? Please describe it
We’re building a multi-tenant app with one subdomain per tenant. All tenants sign in through the same identity provider, but each tenant has its own OIDC client, so different clientIds and secrets. Tenants are created at runtime and stored in our database.
The function form of callbackUrl already covers the subdomain part nicely, thanks for that! As far as we can tell, though, oidc.providers is a static map that’s read once at startup. So adding a tenant, or rotating a tenant’s client secret, would currently need a restart of the app. Please correct us if we missed an existing way to do this.
Describe the solution you'd like
providers: async (name, request) => {
const tenant = await tenants.findByKey(name);
return tenant
? { issuer: tenant.issuer, clientId: tenant.clientId, clientSecret: tenant.clientSecret }
: undefined; // unknown provider → 404, like today
},Drawbacks / open points we can think of (there are probably more we don’t see from the outside):
- The config couldn’t be validated at startup anymore, so it would probably need to be validated when it’s resolved.
- OidcClient instances seem to be cached per provider name. A changed config (e.g. a rotated secret) would need some way to refresh that cache.
- It’s an extra lookup per login/callback, which apps could cache on their side if needed.
We’re very open to a different shape if something else fits the package’s design better.
Teachability, documentation, adoption, migration strategy
This would be purely additive: the existing Record form keeps working, so there’s no migration. In the docs, it could sit right after the paragraph about the callbackUrl function in "Add 'Sign in with Google'", maybe like:
"If your providers aren’t known at startup, for example one OIDC client per customer, pass a function as providers. start() and finish() call it with the provider’s name and the request; return the provider’s config, or undefined for a provider you don’t serve."
What is the motivation / use case for changing the behavior?
Self-service onboarding of new tenants without a redeploy. In B2B setups it’s quite common that each customer brings their own IdP client (or even their own IdP), so the list of providers grows with the customer base rather than being fixed in code.
As a workaround, we currently keep a reference to the providers object and add entries at runtime. It works in 0.1.1, but since it relies on internals we’d feel better with a supported way.
Activity
kamilmysliwiec commentedon Oct 13, 2026
lets track this here #52