Backend guides
Adding an OAuth provider
Register an OAuth provider for sign-in, account linking and re-authentication.
On this page
OAuth providers share the generic sign-in, linking and re-authentication endpoints. Start with the live
IOAuthProvider interface and implementations in api/src/Slicekit.Api/Auth/OAuth/: GitHub is the existing
non-OIDC example, and Google includes ID-token verification. Use those files rather than copying an incomplete
provider skeleton.
Settings and discovery
Add the provider to api/src/Slicekit.Core/Settings/OAuthSettings.cs using OAuthProviderSettings, with validation
for enabled providers. Committed settings contain placeholders; deployment supplies the credentials and redirect
URI. Follow the settings pattern for environment overrides.
Register the implementation in api/src/Slicekit.Api/Configuration/Auth.cs under the global OAuth flag and the
provider’s own flag. Add its lowercase ID to FeaturesEndpoint in api/src/Slicekit.Api/Endpoints/v1/Auth/ as well.
Registration in DI alone does not advertise a new provider to the frontend.
For a Discord settings property, the environment prefix is OAuth__Discord__, followed by Enabled, ClientId,
ClientSecret or RedirectUri. Document these overrides in .env.prod.example and supply them to the API in
your deployment configuration.
Identity contracts
The canonical provider name is persisted with external logins. Do not rename it after use. The factory accepts
route IDs without regard to case, but the stored identity must remain stable. Use the provider’s opaque or numeric
account ID as ExternalId, rather than an email address that can change.
OIDC providers must validate ID tokens, including the expected subject and email checks, through
OidcIdTokenValidator as the Google provider does. Keep the generic endpoints’ state and PKCE handling when adding
a provider; do not introduce another callback or session mechanism.
Frontend entry and icon
Add the lowercase ID and display label to frontend/src/features/oauth/types.ts. Add a local brand icon to
frontend/src/features/oauth/components/OAuthButtons.tsx, following GithubIcon and the inline Google icon.
The map uses React’s ComponentType<{ className?: string }>; another icon package is not required.
Keep the icon decorative with aria-hidden and label the button with the provider name.
Sign-in and account-linking choices are filtered by the enabled-provider response. Keep that response, the frontend ID and the provider factory lookup consistent.
Callback and registration policy
Allowlist the exact frontend callback URI in the provider’s application settings. A local Discord example is
http://localhost:3003/auth/oauth/discord/callback. The provider redirects there with a GET; the SPA then posts
code and state to the API. An API callback accepting only POST cannot serve as the browser redirect destination.
The same SPA callback completes account linking and step-up re-authentication. Preserve the pending operation so each redirect returns to the intended flow.
An OAuth sign-in for an unknown email provisions an account and must respect Auth:RegistrationEnabled. Existing
accounts can still sign in when registration is disabled, and configured bootstrap admins can establish the first
admin account. Enabling a provider must not bypass an invite-only product’s policy.
Verify
- Build the API; run frontend type checking, lint and tests.
- Verify discovery and startup validation with both flags enabled, either flag disabled, and credentials missing.
- Exercise sign-in, linking and OAuth step-up through the same callback.
- Disable registration and confirm unknown accounts are refused while existing accounts can still sign in.
See Authentication for session behavior and Getting started for running the API and SPA together.