|
1 | 1 | # Cookie Authentication |
2 | 2 |
|
3 | | -This module provides cookie-based authentication functionality for protecting endpoints with JWT token cookies. |
4 | | - |
5 | | -## Overview |
6 | | - |
7 | | -The cookie authentication system consists of: |
8 | | -- **CookieAuth decorator**: Marks endpoints as requiring cookie authentication |
9 | | -- **CookieAuthGuard**: Guard that validates JWT tokens from cookies and sets request context |
| 3 | +Cookie-based authentication for protecting endpoints with JWT token cookies. |
10 | 4 |
|
11 | 5 | ## Usage |
12 | 6 |
|
13 | 7 | ### Basic Usage |
14 | 8 |
|
15 | | -To protect an endpoint with cookie authentication, use the `@CookieAuth()` decorator: |
16 | | - |
17 | 9 | ```typescript |
18 | 10 | import { Controller, Get } from '@nestjs/common'; |
19 | 11 | import { CookieAuth } from 'omniboxd/auth/decorators'; |
| 12 | +import { UserId } from 'omniboxd/decorators/user-id.decorator'; |
20 | 13 |
|
21 | 14 | @Controller('api/v1/protected') |
22 | 15 | export class ProtectedController { |
23 | | - |
24 | 16 | @Get('data') |
25 | 17 | @CookieAuth() |
26 | | - getProtectedData() { |
27 | | - return { message: 'This endpoint requires cookie authentication' }; |
| 18 | + getProtectedData(@UserId() userId: string) { |
| 19 | + return { message: 'Authenticated user', userId }; |
28 | 20 | } |
29 | 21 | } |
30 | 22 | ``` |
31 | 23 |
|
32 | | -### Accessing User Data |
33 | | - |
34 | | -To access the user data in your controller, use the common `@UserId` decorator to get the user ID: |
| 24 | +### Authentication Options |
35 | 25 |
|
36 | 26 | ```typescript |
37 | | -import { Controller, Get } from '@nestjs/common'; |
38 | | -import { CookieAuth } from 'omniboxd/auth/decorators'; |
39 | | -import { UserId } from 'omniboxd/decorators/user-id.decorator'; |
40 | | - |
41 | | -@Controller('api/v1/protected') |
42 | | -export class ProtectedController { |
| 27 | +// Strict authentication (default) - throws UnauthorizedException on failure |
| 28 | +@CookieAuth() |
43 | 29 |
|
44 | | - @Get('user-data') |
45 | | - @CookieAuth() |
46 | | - getUserData(@UserId() userId: string) { |
47 | | - return { |
48 | | - userId: userId, |
49 | | - message: 'User authenticated via cookie', |
50 | | - }; |
51 | | - } |
52 | | -} |
| 30 | +// Continue without authentication on failure |
| 31 | +@CookieAuth({ onAuthFail: 'continue' }) |
53 | 32 | ``` |
54 | 33 |
|
55 | 34 | ## Authentication Flow |
56 | 35 |
|
57 | | -The cookie authentication flow works as follows: |
58 | | - |
59 | | -1. **Request**: Client sends request with `token` cookie containing a JWT |
60 | | -2. **Guard Check**: `CookieAuthGuard` checks if the route is decorated with `@CookieAuth()` |
61 | | -3. **Token Extraction**: Guard extracts the JWT token from the `token` cookie |
62 | | -4. **Token Validation**: Guard validates the JWT token using `AuthService.jwtVerify()` |
63 | | -5. **Data Extraction**: Guard extracts user information directly from the JWT payload |
64 | | -6. **Request Enhancement**: If successful, the guard sets the user object on the request (same structure as JWT authentication) |
65 | | -7. **Controller Access**: Controller methods can access user data using common decorators like `@UserId` |
66 | | - |
67 | | -## User Data Structure |
68 | | - |
69 | | -The cookie authentication uses the same user data structure as JWT authentication: |
70 | | - |
71 | | -```typescript |
72 | | -interface User { |
73 | | - id: string; // User ID from JWT token |
74 | | - email?: string; // User's email from JWT token (optional) |
75 | | - username?: string; // User's username from JWT token (optional) |
76 | | - createdAt?: Date; // Not set by cookie auth |
77 | | - updatedAt?: Date; // Not set by cookie auth |
78 | | - deletedAt?: Date; // Not set by cookie auth |
79 | | -} |
80 | | -``` |
81 | | - |
82 | | -## Error Handling |
| 36 | +1. Client sends request with `token` cookie containing a JWT |
| 37 | +2. `CookieAuthGuard` validates the JWT token using `AuthService.jwtVerify()` |
| 38 | +3. User data is extracted from JWT payload and set on `request.user` |
| 39 | +4. Controller methods access user data via `@UserId()` decorator |
83 | 40 |
|
84 | | -The `CookieAuthGuard` throws `UnauthorizedException` in the following cases: |
| 41 | +## Requirements |
85 | 42 |
|
86 | | -- **Missing Token Cookie**: No `token` cookie is provided |
87 | | -- **Invalid Token**: JWT token is invalid or expired |
88 | | -- **Invalid Payload**: Token payload doesn't contain required `sub` field |
89 | | -- **Parameter Decorator**: `@UserId` decorator throws if no user data is available |
90 | | - |
91 | | -## Integration with Other Authentication Methods |
92 | | - |
93 | | -The cookie authentication system works alongside JWT and API key authentication through a multi-guard setup: |
94 | | - |
95 | | -- **Routes with `@CookieAuth()`**: Use cookie authentication |
96 | | -- **Routes with `@APIKeyAuth()`**: Use API key authentication |
97 | | -- **Routes with `@Public()`**: Skip all authentication |
98 | | -- **Regular routes**: Use JWT authentication (default behavior) |
99 | | - |
100 | | -All guards are registered as global guards in the `AuthModule`, with each guard checking for its specific decorator. |
101 | | - |
102 | | -## Cookie Requirements |
103 | | - |
104 | | -The authentication expects: |
105 | 43 | - **Cookie Name**: `token` |
106 | | -- **Cookie Value**: Valid JWT token signed with the application's JWT secret |
107 | | -- **Token Format**: Standard JWT with `sub` field containing the user ID |
108 | | -- **Optional Fields**: JWT may contain `email` and `username` fields |
109 | | - |
110 | | -## Module Structure |
111 | | - |
112 | | -``` |
113 | | -src/auth/cookie/ |
114 | | -├── cookie.auth.decorator.ts # @CookieAuth() decorator |
115 | | -├── cookie-auth.guard.ts # Authentication guard |
116 | | -├── cookie-auth.guard.spec.ts # Guard unit tests |
117 | | -├── index.ts # Module exports |
118 | | -└── README.md # This documentation |
119 | | -``` |
120 | | - |
121 | | -## Example Usage in Controllers |
122 | | - |
123 | | -```typescript |
124 | | -import { Controller, Get, Post, Body } from '@nestjs/common'; |
125 | | -import { CookieAuth, Public } from 'omniboxd/auth/decorators'; |
126 | | -import { UserId } from 'omniboxd/decorators/user-id.decorator'; |
| 44 | +- **Token Format**: Valid JWT with `sub` field (user ID) |
| 45 | +- **Optional Fields**: `email`, `username` |
127 | 46 |
|
| 47 | +## Error Handling |
128 | 48 |
|
129 | | -@Controller('api/v1/dashboard') |
130 | | -export class DashboardController { |
| 49 | +- **Missing/Invalid Token**: Throws `UnauthorizedException` (unless `onAuthFail: 'continue'`) |
| 50 | +- **Invalid Payload**: Throws `UnauthorizedException` if `sub` field missing |
131 | 51 |
|
132 | | - @Public() |
133 | | - @Get('health') |
134 | | - healthCheck() { |
135 | | - return { status: 'ok' }; |
136 | | - } |
| 52 | +## Integration |
137 | 53 |
|
138 | | - @CookieAuth() |
139 | | - @Get('profile') |
140 | | - getProfile(@UserId() userId: string) { |
141 | | - return { |
142 | | - userId: userId, |
143 | | - message: 'User profile data', |
144 | | - }; |
145 | | - } |
146 | | - |
147 | | - @CookieAuth() |
148 | | - @Post('settings') |
149 | | - updateSettings( |
150 | | - @UserId() userId: string, |
151 | | - @Body() settings: any, |
152 | | - ) { |
153 | | - // Update settings for userId |
154 | | - return { success: true }; |
155 | | - } |
156 | | -} |
157 | | -``` |
| 54 | +Works alongside JWT and API key authentication: |
| 55 | +- `@CookieAuth()`: Cookie authentication |
| 56 | +- `@APIKeyAuth()`: API key authentication |
| 57 | +- `@Public()`: Skip authentication |
| 58 | +- Default: JWT authentication |
0 commit comments