forked from nextauthjs/next-auth
/
index.ts
127 lines (111 loc) · 3.9 KB
/
index.ts
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { EncryptJWT, jwtDecrypt } from "jose"
import hkdf from "@panva/hkdf"
import { v4 as uuid } from "uuid"
import { SessionStore } from "../core/lib/cookie"
import type { GetServerSidePropsContext, NextApiRequest } from "next"
import type { NextRequest } from "next/server"
import type { JWT, JWTDecodeParams, JWTEncodeParams, JWTOptions } from "./types"
import type { LoggerInstance } from ".."
export * from "./types"
const DEFAULT_MAX_AGE = 30 * 24 * 60 * 60 // 30 days
const now = () => (Date.now() / 1000) | 0
/** Issues a JWT. By default, the JWT is encrypted using "A256GCM". */
export async function encode(params: JWTEncodeParams) {
const { token = {}, secret, maxAge = DEFAULT_MAX_AGE } = params
const encryptionSecret = await getDerivedEncryptionKey(secret)
return await new EncryptJWT(token)
.setProtectedHeader({ alg: "dir", enc: "A256GCM" })
.setIssuedAt()
.setExpirationTime(now() + maxAge)
.setJti(uuid())
.encrypt(encryptionSecret)
}
/** Decodes a NextAuth.js issued JWT. */
export async function decode(params: JWTDecodeParams): Promise<JWT | null> {
const { token, secret } = params
if (!token) return null
const encryptionSecret = await getDerivedEncryptionKey(secret)
const { payload } = await jwtDecrypt(token, encryptionSecret, {
clockTolerance: 15,
})
return payload
}
export interface GetTokenParams<R extends boolean = false> {
/** The request containing the JWT either in the cookies or in the `Authorization` header. */
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest
/**
* Use secure prefix for cookie name, unless URL in `NEXTAUTH_URL` is http://
* or not set (e.g. development or test instance) case use unprefixed name
*/
secureCookie?: boolean
/** If the JWT is in the cookie, what name `getToken()` should look for. */
cookieName?: string
/**
* `getToken()` will return the raw JWT if this is set to `true`
* @default false
*/
raw?: R
/**
* The same `secret` used in the `NextAuth` configuration.
* Defaults to the `NEXTAUTH_SECRET` environment variable.
*/
secret?: string
decode?: JWTOptions["decode"]
logger?: LoggerInstance | Console
}
/**
* Takes a NextAuth.js request (`req`) and returns either the NextAuth.js issued JWT's payload,
* or the raw JWT string. We look for the JWT in the either the cookies, or the `Authorization` header.
* [Documentation](https://next-auth.js.org/tutorials/securing-pages-and-api-routes#using-gettoken)
*/
export async function getToken<R extends boolean = false>(
params: GetTokenParams<R>
): Promise<R extends true ? string : JWT | null> {
const {
req,
secureCookie = process.env.NEXTAUTH_URL?.startsWith("https://") ??
!!process.env.VERCEL,
cookieName = secureCookie
? "__Secure-next-auth.session-token"
: "next-auth.session-token",
raw,
decode: _decode = decode,
logger = console,
secret = process.env.NEXTAUTH_SECRET,
} = params
if (!req) throw new Error("Must pass `req` to JWT getToken()")
const sessionStore = new SessionStore(
{ name: cookieName, options: { secure: secureCookie } },
{ cookies: req.cookies, headers: req.headers },
logger
)
let token = sessionStore.value
const authorizationHeader =
req.headers instanceof Headers
? req.headers.get("authorization")
: req.headers.authorization
if (!token && authorizationHeader?.split(" ")[0] === "Bearer") {
const urlEncodedToken = authorizationHeader.split(" ")[1]
token = decodeURIComponent(urlEncodedToken)
}
// @ts-expect-error
if (!token) return null
// @ts-expect-error
if (raw) return token
try {
// @ts-expect-error
return await _decode({ token, secret })
} catch {
// @ts-expect-error
return null
}
}
async function getDerivedEncryptionKey(secret: string | Buffer) {
return await hkdf(
"sha256",
secret,
"",
"NextAuth.js Generated Encryption Key",
32
)
}