Skip to content

Passport Strategies — one per auth method, no more

One huge Strategy with `if`s = you can't add a new auth method without risking the existing ones.

nestjs-auth-one-passport-strategy-per-method

Why it matters

Failure modes if this rule is ignored
StakeIf ignored
Hard to change
  • Adding OAuth or API keys means editing one Strategy full of conditionals — existing JWT login can break when you touch the mega-Strategy.
Spreads failure
  • A bug in one auth branch breaks every endpoint using that Strategy.

How to fix

NestJS + Passport invites JwtStrategy, LocalStrategy, ApiKeyStrategy. Each lives in its own file, and makes no business decisions.

Examples

Bad
ts
@Injectable()
export class AuthStrategy extends PassportStrategy(Strategy, 'jwt') {
  async validate(req: Request): Promise<User> {
    const apiKey = req.headers['x-api-key'];
    if (apiKey) return this.apiKeys.resolveOwner(String(apiKey));
    const token = extractJwt(req);
    return this.users.findById(token.sub);
  }
}
Good
ts
// libs/shared/backend-auth/src/lib/jwt.strategy.ts
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
  async validate(payload: JwtPayload): Promise<User> {
    return this.users.findById(payload.sub);
  }
}

// libs/shared/backend-auth/src/lib/api-key.strategy.ts
@Injectable()
export class ApiKeyStrategy extends PassportStrategy(HeaderAPIKeyStrategy, 'api-key') {
  async validate(apiKey: string): Promise<User> {
    return this.apiKeys.resolveOwner(apiKey);
  }
}

// usage — pick a strategy per endpoint
@UseGuards(AuthGuard('jwt'))      // user via UI
@UseGuards(AuthGuard('api-key'))  // external integration
@UseGuards(AuthGuard(['jwt', 'api-key']))  // both

Contribute

Released under the MIT License.

esc