Here’s a comprehensive list of authentication service types (both strategies and mechanisms), with a brief explanation and common use cases — especially helpful for backend apps like those built with NestJS, and frontend integrations via Next.js:
🔐 Common Authentication Strategies
Strategy | Description | Use Case Example |
---|---|---|
Session-based Auth | Stores session ID on server and client via cookies. Server holds the session state. | Classic web apps (e.g., Express, Rails) |
JWT (JSON Web Token) | Stateless, token-based. Token is signed and sent in headers (usually Authorization ). |
Modern SPAs, mobile apps |
OAuth 2.0 | Delegated auth using third-party providers like Google, Facebook, GitHub. | “Login with Google” |
OpenID Connect (OIDC) | Built on top of OAuth 2.0, adds identity layer. Returns id_token . |
Auth0, Azure AD |
API Key Auth | Simple token passed via headers or query params. | Internal services, public APIs |
Basic Auth | Username and password encoded in base64 in the Authorization header. |
Legacy or internal APIs |
Bearer Token | Generic token-based auth (includes JWT, API keys, etc.). | REST APIs |
Mutual TLS (mTLS) | Both client and server verify each other's certificates. | High-security enterprise APIs |
HMAC (Hash-based Message Authentication Code) | Used to sign messages with a shared secret. | Webhooks, AWS API Gateway |
SAML (Security Assertion Markup Language) | XML-based auth, often used in enterprise SSO. | Corporate portals |
Magic Link / Email Link Auth | Auth via secure, expiring link sent to email. No password needed. | Passwordless login |
One-Time Password (OTP) | Temporary code sent via email/SMS or generated by app. | MFA (2FA) flows |
Social Auth | Use third-party providers for identity (Google, Facebook, Apple, etc). | User convenience |
Fingerprint / Biometrics | Device-native auth via fingerprint, FaceID. | Mobile/web PWA apps |
Device/Token Binding | Ties auth token to device or browser instance. | Secure mobile or banking apps |
🧱 Storage Mechanisms for Auth State
Storage Location | Used By | Consideration |
---|---|---|
HTTP-Only Cookies | Session-based, JWT | Secure, not accessible by JS |
LocalStorage | JWT (client-side) | Vulnerable to XSS |
SessionStorage | JWT (session-level) | Cleared on tab close |
In-memory (volatile) | Mobile apps, SPAs | Lost on refresh |
Redis / DB Session Store | Session-based auth | Good for scaling with session persistence |
✅ Advanced Concepts
- Refresh Tokens: Used with JWT to rotate tokens without forcing re-login.
- Multi-Factor Authentication (MFA): OTP, email, biometrics, etc.
- Role-Based Access Control (RBAC): Authorization layer (not auth but closely tied).
- Attribute-Based Access Control (ABAC): Access based on attributes/claims.
- Token Introspection / Revocation: OAuth feature to validate token state dynamically.
🛠️ Popular Services/Providers
Provider | Type | Notes |
---|---|---|
Auth0 | OAuth2/OIDC, SAML, JWT | Full-service auth platform |
Firebase Auth | JWT, OAuth2 | Easy for mobile/web apps |
Clerk | OIDC, Magic Links | Dev-first auth-as-a-service |
Supabase Auth | JWT, OAuth2 | Open-source Firebase alternative |
Okta | OAuth2, SAML, OIDC | Enterprise identity management |
Keycloak | OAuth2, SAML, OpenID | Self-hosted, flexible |
NextAuth.js | Session/JWT/OAuth2 | Next.js-friendly |
Sure, Taki. Here’s a slow, step-by-step breakdown of how to architect a robust authentication system using NestJS (backend) and Next.js (frontend) — covering Session-based, JWT-based, and OAuth2 (with providers like Google) patterns.
🧭 Overview: Auth Patterns
I'll cover 3 patterns with full architecture and how they integrate:
- Session-based Auth – Secure, cookie-stored sessions with a backend session store (e.g., Redis).
- JWT-based Auth (Access + Refresh Tokens) – Stateless, token-based with refresh flow.
- OAuth2/OIDC Login – Login with Google/GitHub using OAuth2.
Let’s go deep — starting with Pattern #1.
🔐 PATTERN 1: SESSION-BASED AUTH (NestJS + Next.js)
✅ When to Use:
- You need HTTP-only cookies.
- CSRF protection is important.
- You want the server to manage session lifecycle (central logout, etc.).
- Excellent for SSR with Next.js.
⚙️ High-Level Architecture:
[ Next.js Client ] <-> [ NestJS Backend (Express adapter) + Session Store (Redis) ]
|
Cookies (HttpOnly, Secure)
|
[ Auth Session stored on server (via session ID) ]
🧱 Step-by-Step Implementation
1. 📦 NestJS Backend Setup
a. Install dependencies:
npm install @nestjs/passport passport passport-local express-session connect-redis ioredis
npm install @nestjs/platform-express
b. Enable Express Session (in main.ts
):
import * as session from 'express-session';
import * as connectRedis from 'connect-redis';
import { createClient } from 'redis';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const RedisStore = connectRedis(session);
const redisClient = createClient();
app.use(
session({
store: new RedisStore({ client: redisClient }),
secret: 'your-secret',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: true, // true in production
maxAge: 1000 * 60 * 60, // 1 hour
},
}),
);
await app.listen(3001);
}
c. Set up Local Auth (Passport):
-
local.strategy.ts
:
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super(); // uses username/password fields by default
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) throw new UnauthorizedException();
return user;
}
}
-
auth.controller.ts
:
@UseGuards(AuthGuard('local'))
@Post('login')
login(@Request() req): any {
return req.user; // user info is now in session
}
@Get('profile')
getProfile(@Request() req) {
return req.user; // automatically loaded from session
}
-
auth.service.ts
:
@Injectable()
export class AuthService {
async validateUser(username: string, password: string): Promise<any> {
const user = await this.usersService.findOne(username);
if (user && user.password === password) {
const { password, ...rest } = user;
return rest;
}
return null;
}
}
2. 🧼 Next.js Frontend Setup
a. Use fetch
with credentials: 'include'
// login.ts
const login = async (username: string, password: string) => {
const res = await fetch('http://localhost:3001/auth/login', {
method: 'POST',
credentials: 'include', // important for cookies
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
});
const data = await res.json();
return data;
};
b. Use getServerSideProps
with cookie
You can access the session via cookie in SSR.
3. 🔒 Secure It for Production
- Use HTTPS (for
secure: true
cookie). - Use CSRF protection if modifying server state.
- Store session secrets securely (e.g.,
.env
+ vault).
✅ Pros & Cons
✅ Pros | ❌ Cons |
---|---|
Works well with SSR | Less scalable (stateful) |
HttpOnly cookies (XSS-safe) | Redis or DB session storage |
Central logout & session control | CSRF concerns |
✅ Ready to go stateless? Let’s move on to Pattern 2: JWT Auth.
🔐 PATTERN 2: JWT-BASED AUTH (Access + Refresh)
✅ When to Use:
- Mobile or SPAs (Next.js API routes, no SSR)
- Stateless services (microservices)
- You want scalability without session stores
⚙️ Architecture:
[ Next.js Client ] ⇄ [ NestJS Auth API ]
| |
LocalStorage JWT Access Token (short-lived)
Refresh Token (Cookie or DB) ⇄ /auth/refresh
🧱 Implementation Steps
1. 📦 NestJS Backend Setup
a. Install packages
npm install @nestjs/jwt passport-jwt
b. Configure JWT strategy
-
jwt.strategy.ts
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'jwt-secret',
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}
c. Issue JWTs
-
auth.service.ts
async login(user: any) {
const payload = { username: user.username, sub: user.id };
const accessToken = this.jwtService.sign(payload, { expiresIn: '15m' });
const refreshToken = this.jwtService.sign(payload, { expiresIn: '7d' });
return { accessToken, refreshToken };
}
- Store refresh token in DB or send it in secure HTTP-only cookie.
2. 🔄 Refresh Token Endpoint
@Post('refresh')
refresh(@Body() body) {
const valid = this.jwtService.verify(body.refreshToken);
const accessToken = this.jwtService.sign({ ...valid }, { expiresIn: '15m' });
return { accessToken };
}
3. 🧼 Next.js Frontend Setup
- Store
accessToken
in memory orlocalStorage
- Auto-attach
Authorization: Bearer <token>
to each request - On 401 → trigger
/auth/refresh
✅ Pros & Cons
✅ Pros | ❌ Cons |
---|---|
Stateless (scales easily) | Refresh token complexity |
Works well on mobile | Vulnerable if token leaked |
Easy to implement | Needs secure token rotation |
Up next: Pattern 3 – OAuth2 / Google Login (e.g., "Sign in with Google")
🌐 PATTERN 3: OAuth2 (Login with Google) – NestJS + Next.js
✅ When to Use
✅ Ideal For |
---|
User-friendly social login |
Offloading identity verification to Google, etc |
Supporting SSO in enterprise (via OIDC) |
Not storing passwords in your DB |
⚙️ Architecture
[ Next.js Client ]
↓ click
[ Google Login Button ]
↓ redirect
[ NestJS OAuth Controller ]
→ [ Google Auth ]
← Access Token + Profile
→ Issue JWT / Session internally
📌 Goals
- Redirect user to Google OAuth
- Receive Google user profile
- Create or find user in DB
- Return your own JWT or session cookie to frontend
🧱 Step-by-Step: NestJS Backend
1. 📦 Install Required Packages
npm install passport passport-google-oauth20 @nestjs/passport
2. 📁 Create Google Strategy
google.strategy.ts
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { Strategy, VerifyCallback } from 'passport-google-oauth20';
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor() {
super({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: 'http://localhost:3001/auth/google/redirect',
scope: ['email', 'profile'],
});
}
async validate(accessToken: string, refreshToken: string, profile: any, done: VerifyCallback): Promise<any> {
const { name, emails, photos } = profile;
const user = {
email: emails[0].value,
firstName: name.givenName,
lastName: name.familyName,
picture: photos[0].value,
accessToken,
};
done(null, user);
}
}
3. 📁 Auth Controller for Google
auth.controller.ts
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
@Get('google')
@UseGuards(AuthGuard('google'))
async googleLogin() {
// Redirects to Google
}
@Get('google/redirect')
@UseGuards(AuthGuard('google'))
async googleRedirect(@Req() req: Request, @Res() res: Response) {
const user = req.user; // Google profile
const jwt = await this.authService.googleLogin(req.user); // Issue JWT
res.cookie('jwt', jwt, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
});
return res.redirect('http://localhost:3000/dashboard');
}
}
4. 🧠 Auth Service Logic
auth.service.ts
async googleLogin(googleUser: any): Promise<string> {
const user = await this.usersService.findOrCreate(googleUser.email, googleUser);
const payload = { sub: user.id, email: user.email };
return this.jwtService.sign(payload);
}
5. 🧩 Plug in GoogleStrategy
auth.module.ts
@Module({
providers: [AuthService, GoogleStrategy],
controllers: [AuthController],
})
export class AuthModule {}
🧼 Next.js Frontend
1. 🔘 Login Button
// /login.tsx
const handleGoogleLogin = () => {
window.location.href = 'http://localhost:3001/auth/google';
};
2. 🔐 Protected Pages (SSR / Client)
Client-side (token from cookie):
- You can use
getServerSideProps
and read cookie to validate user. - OR store JWT from backend in localStorage and attach manually.
✅ Summary: Pros & Cons
✅ Pros | ❌ Cons |
---|---|
No password management | Requires setting up OAuth apps |
Trust Google/Facebook/etc | Depends on 3rd party availability |
Easy login UX | May not work for internal users |
Works with JWT or Session backend | Token exchange complexity |
🔒 Security Tips
- Always use
https
+httpOnly
cookies if possible - Handle token expiration
- Optional: bind session to IP/device
- Optional: add MFA after social login
🧪 Optional Enhancements
- Add GitHub / Facebook / Microsoft login by replicating strategy
- Support OIDC Enterprise providers (e.g., Azure AD)
- Store refresh token from Google if you want to call Google APIs
- Combine with role-based access
Top comments (0)