forked from effect-app/boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauth.ts
More file actions
87 lines (79 loc) · 2.84 KB
/
auth.ts
File metadata and controls
87 lines (79 loc) · 2.84 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
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable unused-imports/no-unused-vars */
import { HttpHeaders, HttpMiddleware, HttpServerRequest, HttpServerResponse } from "api/lib/http"
import { Config, Effect } from "effect-app"
import {
auth,
InsufficientScopeError,
InvalidRequestError,
InvalidTokenError,
UnauthorizedError
} from "express-oauth2-jwt-bearer"
// // Authorization middleware. When used, the Access Token must
// // exist and be verified against the Auth0 JSON Web Key Set.
export const Auth0Config = Config.all({
audience: Config.string("audience").pipe(Config.nested("auth0"), Config.withDefault("http://localhost:3610")),
issuer: Config.string("issuer").pipe(
Config.nested("auth0"),
Config.withDefault("https://effect-app-boilerplate-dev.eu.auth0.com")
)
})
// type Errors = InsufficientScopeError | InvalidRequestError | InvalidTokenError | UnauthorizedError
export const checkJWTI = (config: Effect.Success<typeof Auth0Config>) => {
const mw = auth({
audience: config.audience,
issuer: config.issuer + "/",
jwksUri: `${config.issuer}/.well-known/jwks.json`
})
return Effect.gen(function*($) {
const req = yield* $(HttpServerRequest.ServerRequest)
return yield* $(
Effect.async<void, InsufficientScopeError | InvalidRequestError | InvalidTokenError | UnauthorizedError>(
(cb) => {
const next = (err?: unknown) => {
if (!err) return cb(Effect.unit)
if (
err instanceof InsufficientScopeError
|| err instanceof InvalidRequestError
|| err instanceof InvalidTokenError
|| err instanceof UnauthorizedError
) {
return cb(Effect.fail(err))
}
return Effect.die(err)
}
const r = { headers: req.headers, query: {}, body: {}, is: () => false } // is("urlencoded")
try {
mw(r as any, {} as any, next)
} catch (e) {
return cb(Effect.die(e))
}
}
)
)
})
}
export const checkJwt = (config: Effect.Success<typeof Auth0Config>) => {
const check = checkJWTI(config)
return HttpMiddleware.make((app) =>
Effect.gen(function*($) {
const response = yield* $(Effect.catchAll(check, (e) =>
Effect.succeed(
HttpServerResponse.unsafeJson({ message: e.message }, {
status: e.status,
headers: HttpHeaders.fromInput(e.headers)
})
)))
if (response) {
return response
}
return yield* $(app)
})
)
}
// const checkScopes = requiredScopes('read:messages');
// app.get('/api/private-scoped', checkJwt, checkScopes, function(req, res) {
// res.json({
// message: 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.'
// });
// });