Paradise CodeSoftware Studio
Back to articles
SecurityUpdated 17 min read

Authentication with JWT, Refresh Tokens, and RBAC in NestJS

Design access/refresh flows, token rotation, session revocation, and role/permission checks without scattering security logic across controllers.

JWTNestJSRBACauthenticationsecurity

Ali Mortazavi

Founder, Paradise Code

Short-lived access, protected refresh

Access tokens should live minutes, not days, and carry only required claims: `sub`, `tenantId`, roles or a permission version. Refresh tokens live longer but need safer storage—httpOnly cookies with proper Secure/SameSite, or strict mobile secure storage—and must be revocable server-side.

Stateless JWTs work well for access; for refresh, without server-side tracking (token record, token family, or revocation list) you cannot contain theft.

Refresh rotation and theft detection

On every refresh use, revoke the old token and issue a new one (rotation). If a revoked token is reused, revoke the entire session family—that is a classic replay/theft signal. This is far safer than “one refresh forever.”

Keep session metadata: user agent, coarse IP, created at, last used. Let users “sign out everywhere”; that is a security feature, not a settings luxury.

RBAC and real product permissions

Roles alone are not enough. Map roles to stable permissions (`invoice:read`, `invoice:write`). In Nest, build guards on permissions, not hard-coded role strings in every controller. The permission source of truth can be a compact JWT version plus cache, or a controlled DB read for sensitive operations.

In multi-tenant SaaS, roles are meaningful inside a tenant. Never evaluate permission without `tenantId`. IDOR tests belong in your security CI.

Nest layering: a clean Auth module

Keep Passport/JWT strategies thin: extract token, verify signature, load user context. Leave login business rules, lockouts, and audit in domain services. Rate-limit login/refresh/forgot-password paths.

Normalize errors to reduce oracles—“invalid email or password” instead of revealing account existence on every path—balanced with UX your product accepts. For sensitive routes, keep security logs without passwords or excess PII.

Token storage on web and mobile

In web SPAs, access in memory plus refresh in an httpOnly cookie is a common pattern that makes XSS theft of refresh harder—with matching CSRF protection. localStorage for refresh is usually wrong. On mobile, use OS secure storage.

Keep CORS and cookie domains minimal. An overly open domain voids the security model.

Revocation, password changes, and security events

Password changes, role upgrades, or anomaly detection should revoke sessions or expire access sooner (e.g. a user `tokenVersion`). Relying only on access expiry is not enough.

For sensitive operations (email change, money out), consider re-auth or step-up with a second factor. RBAC limits access; operation sensitivity needs another layer.

Pre-production checklist

Review modern signing algorithms, key rotation, secrets in a vault/secure env, tested refresh rotation, and a global logout path. Treat auth penetration tests as seriously as commercial features.

Authentication security is a brand moment: one bug here breaks trust in the whole product. In serious implementations, this layer is locked before UI polish.

Frequently asked questions

What is a good access token lifetime?

Often 5–15 minutes for web. Shorter is safer when your refresh flow and UX are smooth.

Is a JWT refresh token enough with no server storage?

Not for a strong model. You need at least server-side tracking/revocation or a token family.

Put permissions in the JWT or read the DB every time?

For hot paths, compact claims or a versioned cache; for sensitive operations, fresh checks against the source of truth.

Is SameSite=Lax enough?

It depends on your cross-site model. Sensitive cookies often combine Strict or Lax with an explicit CSRF token. Design for your product’s real needs.

Insights

Need these ideas implemented in your product?

Paradise Code supports you from consult to full delivery.

Request collaboration