-
Notifications
You must be signed in to change notification settings - Fork 181
Expand file tree
/
Copy pathauthentication-authorization.test.ts
More file actions
99 lines (82 loc) · 2.61 KB
/
authentication-authorization.test.ts
File metadata and controls
99 lines (82 loc) · 2.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
* Tests for Authentication & Authorization Recipe
*/
import { describe, it } from 'node:test';
import * as assert from 'node:assert';
import * as http from 'node:http';
import Router, { RouterContext } from '../router-module-loader';
import request from 'supertest';
import Koa from 'koa';
import { Next } from '../common';
describe('Authentication & Authorization', () => {
it('should authenticate requests with JWT token', async () => {
const app = new Koa();
const router = new Router();
const User = {
findById: async (id: string) => ({ id, name: 'John', role: 'user' })
};
const jwt = {
verify: (token: string, _secret: string) => {
if (token === 'valid-token') {
return { userId: '123' };
}
throw new Error('Invalid token');
}
};
const authenticate = async (ctx: RouterContext, next: Next) => {
const authHeader = ctx.headers.authorization || ctx.headers.Authorization;
const token =
typeof authHeader === 'string'
? authHeader.replace('Bearer ', '')
: undefined;
if (!token) {
ctx.throw(401, 'Authentication required');
return;
}
try {
const decoded = jwt.verify(token, 'secret') as { userId: string };
ctx.state.user = await User.findById(decoded.userId);
return next();
} catch (err) {
ctx.throw(401, 'Invalid token');
return;
}
};
const requireRole =
(role: string) => async (ctx: RouterContext, next: Next) => {
if (!ctx.state.user) {
ctx.throw(401, 'Authentication required');
}
if (ctx.state.user.role !== role) {
ctx.throw(403, 'Insufficient permissions');
}
await next();
};
router.get('/profile', authenticate, async (ctx: RouterContext) => {
ctx.body = ctx.state.user;
});
router.get(
'/admin',
authenticate,
requireRole('admin'),
async (ctx: RouterContext) => {
ctx.body = { message: 'Admin access granted' };
}
);
app.use(router.routes());
app.use(router.allowedMethods());
const res1 = await request(http.createServer(app.callback()))
.get('/profile')
.set('Authorization', 'Bearer valid-token')
.expect(200);
assert.strictEqual(res1.body.id, '123');
assert.strictEqual(res1.body.name, 'John');
await request(http.createServer(app.callback()))
.get('/profile')
.expect(401);
await request(http.createServer(app.callback()))
.get('/admin')
.set('Authorization', 'Bearer valid-token')
.expect(403);
});
});