Auth guards are the most common real-world use of the guard mechanism, verifying that a request carries valid credentials before it reaches a protected route. This lesson builds a simple token-based auth guard.
A Basic Auth Guard
An auth guard typically extracts a token from the Authorization header, verifies it, and attaches the resulting user information onto the request object so later handlers and services can access it.
Attaching request.user here lets a later custom decorator (like @CurrentUser()) or controller logic access the authenticated user without repeating the token verification logic.
Return false (or throw UnauthorizedException) when credentials are missing or invalid.
Attach the resolved user to the request so downstream code doesn't re-verify the token.
For real projects, prefer Passport strategies (covered later) over hand-rolled token parsing.
Keep token verification logic in a service, not inline in the guard, so it's independently testable.
Auth Guard Cheatsheet
Key pieces of a typical authentication guard.
Piece
Purpose
Authorization header
Carries the bearer token from the client
Token verification service
Validates and decodes the token
request.user
Where the authenticated user is commonly attached
UnauthorizedException
Thrown for missing or invalid credentials
Throwing UnauthorizedException vs Returning False
Returning false from canActivate() results in a generic 403 Forbidden with no message. Throwing UnauthorizedException('Invalid token') instead produces a proper 401 with a descriptive message, generally the better choice for authentication failures specifically.
if (!token) {
throw new UnauthorizedException('Missing bearer token');
}
Allowing Public Routes to Skip the Guard
A global auth guard needs a way to skip specific public routes (like login or health checks). A custom @Public() decorator combined with Reflector lets the guard check for that metadata and bypass verification when present.
Returning a generic false instead of throwing a descriptive UnauthorizedException.
Hardcoding token verification logic inline instead of delegating to a testable service.
Applying a global auth guard without a mechanism to exempt public routes like /login.
Not attaching the resolved user to the request, forcing every downstream handler to re-verify.
Key Takeaways
Auth guards verify credentials and decide whether a request may proceed.
Throwing UnauthorizedException gives clients a clearer 401 response than returning false.
Attaching the authenticated user to the request avoids repeated verification downstream.
A @Public() metadata decorator lets specific routes opt out of a global auth guard.
Pro Tip
Build the @Public() decorator and metadata check before you ever apply an auth guard globally, retrofitting an escape hatch after every route already requires authentication is much more error-prone than designing it in from the start.
You now know how to protect routes with an auth guard. Next, extend this with Role-Based Access to control what authenticated users can do.