Skip to content

Commit 662adc4

Browse files
committed
update 06
1 parent 508b282 commit 662adc4

78 files changed

Lines changed: 8017 additions & 539 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

06-rest-api/02-auth/06-login-app-cookies/README.md

Lines changed: 99 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@
22

33
In this example we will implement security and redirect to login page if is not authorized using a JWT token in Cookies.
44

5-
# Steps to build it
5+
## Install dependencies
66

7-
- `npm install` to install packages:
7+
`npm install` to install packages:
88

99
```bash
10+
cd back
1011
npm install
1112
```
1213

13-
- Start `back` app:
14+
```bash
15+
cd front
16+
npm install
17+
```
18+
19+
## Start apps
20+
21+
Start `back` app:
1422

1523
```bash
1624
cd ./back
@@ -19,31 +27,47 @@ npm start
1927

2028
> NOTE: We added `.env` file only for demo purpose. We should ignore this one and add a `.env.example` as example.
2129
22-
- Let's install `cookie-parser` to save token in a cookie (backend project):
30+
Start `front` app:
31+
32+
```bash
33+
cd ./front
34+
npm start
35+
```
36+
37+
## Configure cookies
38+
39+
Let's install `cookie-parser` to save token in a cookie (backend project):
2340

2441
```bash
2542
npm install cookie-parser --save
2643
```
2744

28-
- Configure it:
45+
Configure it:
2946

30-
_./back/src/core/servers/express.server.ts_
47+
_./back/src/core/servers/rest-api.server.ts_
3148

3249
```diff
3350
import express from 'express';
51+
import cors from 'cors';
3452
+ import cookieParser from 'cookie-parser';
3553

36-
export const createApp = () => {
54+
export const createRestApiServer = () => {
3755
const app = express();
38-
3956
app.use(express.json());
57+
app.use(
58+
cors({
59+
credentials: true,
60+
origin: '*',
61+
})
62+
);
4063
+ app.use(cookieParser());
64+
4165
return app;
4266
};
4367

4468
```
4569

46-
- Remove `token` from body:
70+
Remove `token` from body:
4771

4872
_./back/src/pods/security/security.api-model.ts_
4973

@@ -71,7 +95,7 @@ const createUserSession = (user: User): UserSession => {
7195

7296
```
7397

74-
- Update login method:
98+
Update login method:
7599

76100
_./back/src/pods/security/security.api.ts_
77101

@@ -87,8 +111,7 @@ _./back/src/pods/security/security.api.ts_
87111
if (currentUser) {
88112
const userSession = createUserSession(currentUser);
89113
+ const token = createToken(currentUser);
90-
91-
+ res.cookie(headerConstants.authorization, token);
114+
+ res.cookie(HEADERS.AUTHORIZATION, token);
92115
res.send(userSession);
93116
} else {
94117
res.sendStatus(401);
@@ -97,19 +120,19 @@ _./back/src/pods/security/security.api.ts_
97120

98121
```
99122

100-
- Add cookie options:
123+
Add cookie options:
101124

102125
_./back/src/pods/security/security.constants.ts_
103126

104127
```diff
105128
+ import { CookieOptions } from 'express';
106-
+ import { envConstants } from 'core/constants';
129+
+ import { ENV } from '#core/constants/index.js';
107130

108-
export const jwtSignAlgorithm = 'HS256';
131+
export const JWT_SIGN_ALGORITHM = 'HS256';
109132

110-
+ export const cookieOptions: CookieOptions = {
133+
+ export const COOKIE_OPTIONS: CookieOptions = {
111134
+ httpOnly: true,
112-
+ secure: envConstants.isProduction,
135+
+ secure: ENV.IS_PRODUCTION,
113136
+ };
114137

115138
```
@@ -118,8 +141,8 @@ _./back/src/pods/security/security.api.ts_
118141
```diff
119142
...
120143
import { jwtMiddleware } from './security.middlewares';
121-
- import { jwtSignAlgorithm } from './security.constants';
122-
+ import { jwtSignAlgorithm, cookieOptions } from './security.constants';
144+
- import { JWT_SIGN_ALGORITHM } from './security.constants.js';
145+
+ import { JWT_SIGN_ALGORITHM, COOKIE_OPTIONS } from './security.constants.js';
123146
...
124147

125148
.post('/login', async (req, res) => {
@@ -131,9 +154,8 @@ import { jwtMiddleware } from './security.middlewares';
131154
if (currentUser) {
132155
const userSession = createUserSession(currentUser);
133156
const token = createToken(currentUser);
134-
135-
- res.cookie(headerConstants.authorization, token);
136-
+ res.cookie(headerConstants.authorization, token, cookieOptions);
157+
- res.cookie(HEADERS.AUTHORIZATION, token);
158+
+ res.cookie(HEADERS.AUTHORIZATION, token, COOKIE_OPTIONS);
137159
res.send(userSession);
138160
} else {
139161
res.sendStatus(401);
@@ -142,35 +164,35 @@ import { jwtMiddleware } from './security.middlewares';
142164

143165
```
144166

145-
- Update security middleware to read cookies:
167+
Update security middleware to read cookies:
146168

147169
_./back/src/pods/security/security.middlewares.ts_
148170

149171
```diff
150172
import { Request } from 'express';
151173
import expressJwt from 'express-jwt';
152-
import { envConstants, headerConstants } from 'core/constants';
153-
import { jwtSignAlgorithm } from './security.constants';
174+
import { ENV, HEADERS } from '#core/constants/index.js';
175+
import { JWT_SIGN_ALGORITHM } from './security.constants.js';
154176

155177
export const jwtMiddleware = expressJwt({
156-
secret: envConstants.TOKEN_AUTH_SECRET,
157-
algorithms: [jwtSignAlgorithm],
178+
secret: ENV.TOKEN_AUTH_SECRET,
179+
algorithms: [JWT_SIGN_ALGORITHM],
158180
getToken: (req: Request) => {
159181
- const tokenWithBearer = req.headers
160182
+ const tokenWithBearer = req.cookies
161-
- ? (req.headers[headerConstants.authorization] as string)
162-
+ ? (req.cookies[headerConstants.authorization] as string)
183+
- ? (req.headers[HEADERS.AUTHORIZATION] as string)
184+
+ ? (req.cookies[HEADERS.AUTHORIZATION] as string)
163185
: '';
164186

165-
const [, token] = tokenWithBearer.split(`${headerConstants.bearer} `) || [];
187+
const [, token] = tokenWithBearer.split(`${HEADERS.BEARER} `) || [];
166188

167189
return token;
168190
},
169191
});
170192

171193
```
172194

173-
- Implement logout method:
195+
Implement logout method:
174196

175197
_./back/src/pods/security/security.api.ts_
176198

@@ -181,71 +203,69 @@ _./back/src/pods/security/security.api.ts_
181203
// Different approaches:
182204
// - Short expiration times in token
183205
// - Black list tokens on DB
184-
+ res.clearCookie(headerConstants.authorization);
206+
+ res.clearCookie(HEADERS.AUTHORIZATION);
185207
res.sendStatus(200);
186208
});
187209
```
188210

189-
- Notice that we don't need to update the front code to run example.
211+
> Try to login and get list using the frontend app.
212+
>
213+
> We need extra configuration to make it works Cookies with CORS.
190214
215+
Restore proxy configuration:
191216

192-
## Cookie expiration
217+
_./front/vite.config.ts_
193218

194-
Right now, cookie expires when users close the browser. We could add some expiration time:
219+
```diff
220+
import { defineConfig } from 'vite';
221+
import react from '@vitejs/plugin-react';
222+
223+
export default defineConfig({
224+
plugins: [react()],
225+
+ server: {
226+
+ proxy: {
227+
+ '/api': 'http://localhost:3000',
228+
+ },
229+
+ },
230+
});
195231

196-
_./back/src/pods/security/security.constants.ts_
232+
```
197233

198-
```diff
199-
import { CookieOptions } from 'express';
200-
import { envConstants } from 'core/constants';
234+
_./front/src/pods/login/api/login.api.ts_
201235

202-
export const jwtSignAlgorithm = 'HS256';
236+
```diff
237+
...
203238

204-
- export const cookieOptions: CookieOptions = {
205-
- httpOnly: true,
206-
- secure: envConstants.isProduction
207-
- };
239+
- const url = 'http://localhost:3000/api/security/login';
240+
+ const url = '/api/security/login';
208241

209-
+ export const getCookieOptions = (expires: Date): CookieOptions => ({
210-
+ httpOnly: true,
211-
+ secure: envConstants.isProduction,
212-
+ expires,
213-
+ });
242+
...
214243

215244
```
216245

217-
_./back/src/pods/security/security.api.ts_
246+
_./front/src/pods/list/api/list.api.ts_
218247

219248
```diff
220249
...
221-
- import { jwtSignAlgorithm, cookieOptions } from './security.constants';
222-
+ import { jwtSignAlgorithm, getCookieOptions } from './security.constants';
250+
251+
- const clientUrl = 'http://localhost:3000/api/clients';
252+
+ const clientUrl = '/api/clients';
253+
- const orderUrl = 'http://localhost:3000/api/orders';
254+
+ const orderUrl = '/api/orders';
223255

224256
...
225257

226-
.post('/login', async (req, res) => {
227-
const { user, password } = req.body;
228-
const currentUser = userList.find(
229-
(u) => u.userName == user && u.password === password
230-
);
258+
```
231259

232-
if (currentUser) {
233-
const userSession = createUserSession(currentUser);
234-
const token = createToken(currentUser);
235-
+ const expires = new Date();
236-
+ expires.setDate(new Date().getDate() + 1); // Add one day
237-
238-
res.cookie(
239-
headerConstants.authorization,
240-
token,
241-
- cookieOptions
242-
+ getCookieOptions(expires)
243-
);
244-
res.send(userSession);
245-
} else {
246-
res.sendStatus(401);
247-
}
248-
})
260+
_./front/src/core/app-bar/api/app-bar.api.ts_
261+
262+
```diff
263+
...
264+
265+
- const url = 'http://localhost:3000/api/security/logout';
266+
+ const url = '/api/security/logout';
267+
268+
...
249269

250270
```
251271

@@ -257,19 +277,19 @@ _./back/src/pods/security/security.constants.ts_
257277

258278
```diff
259279
import { CookieOptions } from 'express';
260-
import { envConstants } from 'core/constants';
280+
import { ENV } from '#core/constants/index.js';
261281

262-
export const jwtSignAlgorithm = 'HS256';
282+
export const JWT_SIGN_ALGORITHM = 'HS256';
263283

264-
export const cookieOptions: CookieOptions = {
284+
export const COOKIE_OPTIONS: CookieOptions = {
265285
- httpOnly: true,
266286
+ httpOnly: false,
267-
secure: envConstants.isProduction,
287+
secure: ENV.IS_PRODUCTION,
268288
};
269289

270290
```
271291

272-
- Now we could write this code in browser console:
292+
Now we could write this code in browser console:
273293

274294
```
275295
document.cookie

06-rest-api/02-auth/06-login-app-cookies/back/.babelrc

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
NODE_ENV=development
2-
PORT=8081
2+
PORT=3000
33
TOKEN_AUTH_SECRET=MY_TOKEN_AUTH_SECRET
44
ACCESS_TOKEN_EXPIRES_IN=1d

06-rest-api/02-auth/06-login-app-cookies/back/.gitignore

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)