OAuth
OAuth login uses Passport strategies and a provider registry that auto-detects which providers are configured at boot. Only Google is included by default, but the registry is designed for extension.
Architecture
Section titled “Architecture”Three files form the registry:
| File | Role |
|---|---|
oauth/oauth-providers.ts |
Defines each provider: name, enable-check, and strategy factory. |
oauth/oauth-strategy.registry.ts |
OnModuleInit service that iterates providers at boot and registers enabled ones with Passport. |
guards/oauth/oauth.guard.ts |
Guard factory OAuthGuard(provider) that returns 404 if the provider is not enabled. |
CLI prompt / --oauth-providers │ ▼ .env.example → .env (stripped for unselected providers) │ ▼ boot OAuthStrategyRegistry.onModuleInit() │ ├── isEnabled(config) → clientID / secret / callbackURL are set? │ yes → passport.use('google', strategy) │ no → skip, log warning │ ▼ GET /api/v1/authentication/oauth/google │ ▼ OAuthGuard('google').canActivate() ├── registry.isEnabled('google')? → false → 404 │ → true → redirect to Google │ ▼ GET .../oauth/google/callback │ ▼ GoogleStrategy.verify(profile) → AuthenticationService.logOauthUser(profile) → find-or-create user → sessionProvider definition
Section titled “Provider definition”Each provider in OAUTH_PROVIDERS[] implements this shape:
interface OAuthProviderDefinition { name: string; isEnabled(config: AuthConfig): boolean; buildStrategy(config: AuthConfig, verify: OAuthVerifyCallback): unknown;}The isEnabled check returns true only when all three env variables (client ID,
client secret, callback URL) are present and not the your-... placeholder. A
provider whose .env values are left as defaults is skipped silently at boot.
Adding a new provider means adding one entry to OAUTH_PROVIDERS[], a
passport-* dependency to package.json, and two controller endpoints.
Registry boot sequence
Section titled “Registry boot sequence”OAuthStrategyRegistry runs on module init:
- Iterates
OAUTH_PROVIDERS. - Calls
provider.isEnabled(config)for each. - If enabled, calls
provider.buildStrategy(config, verify)which creates the Passport strategy instance and registers it withpassport.use(name, strategy). - If disabled, logs a warning and continues.
The verify callback delegates to AuthenticationService.logOauthUser, which
performs a find-or-create against the user repository.
OAuthGuard is a guard factory — call OAuthGuard('google') to get a NestJS
guard class. Before delegating to Passport, canActivate checks
registry.isEnabled(provider). If the provider was not enabled at boot (missing
or placeholder env vars), it throws NotFoundException immediately, bypassing
Passport entirely.
Routes
Section titled “Routes”GET /api/v1/authentication/oauth/google— starts the Google OAuth flow.GET /api/v1/authentication/oauth/google/callback— handles the callback, creates a session, and redirects to the frontend.
Both routes are exempt from CSRF in main.ts.
CLI integration
Section titled “CLI integration”The scaffolder asks which OAuth providers you need (currently Google). Unselected
providers have their env block stripped from the generated .env, so they can
never activate at boot. Use --oauth-providers google in non-interactive mode.
Next steps
Section titled “Next steps”After scaffolding, fill in your Google OAuth credentials in .env:
GOOGLE_OAUTH_CLIENT_ID=actual-client-idGOOGLE_OAUTH_CLIENT_SECRET=actual-client-secretGOOGLE_OAUTH_CALLBACK_URL=http://localhost:3000/api/v1/authentication/oauth/google/callbackOnce configured, the registry enables the strategy at boot and the OAuth endpoints are ready.