diff --git a/app/.env.local.example b/app/.env.local.example index f45c3fcc83..513dfe1935 100644 --- a/app/.env.local.example +++ b/app/.env.local.example @@ -7,7 +7,7 @@ NEXTAUTH_URL=http://localhost:3000 # https://generate-secret.vercel.app/32 to generate a secret. # Note: Changing a secret may invalidate existing sessions # and/or verification tokens. -SECRET=secret +NEXTAUTH_SECRET=secret AUTH0_ID= AUTH0_SECRET= diff --git a/app/pages/api/auth/[...nextauth].ts b/app/pages/api/auth/[...nextauth].ts index 6c97c06b9c..1220c27fee 100644 --- a/app/pages/api/auth/[...nextauth].ts +++ b/app/pages/api/auth/[...nextauth].ts @@ -189,9 +189,8 @@ export const authOptions: NextAuthOptions = { PatreonProvider({ clientId: process.env.PATREON_ID, clientSecret: process.env.PATREON_SECRET, - }) + }), ], - secret: process.env.SECRET, debug: true, theme: { colorScheme: "auto", diff --git a/src/core/types.ts b/src/core/types.ts index 5f4589d05f..67c4e8a862 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -27,9 +27,10 @@ export interface NextAuthOptions { providers: Provider[] /** * A random string used to hash tokens, sign cookies and generate cryptographic keys. - * If not specified is uses a hash of all configuration options, including Client ID / Secrets for entropy. - * The default behavior is volatile, and **it is strongly recommended** you explicitly specify a value - * to avoid invalidating end user sessions when configuration changes are deployed. + * If not specified, it falls back to `jwt.secret` or `NEXTAUTH_SECRET` from environment vairables. + * Otherwise it will use a hash of all configuration options, including Client ID / Secrets for entropy. + * + * NOTE: The last behavior is extrmely volatile, and will throw an error in production. * * **Default value**: `string` (SHA hash of the "options" object) * * **Required**: No - **but strongly recommended**! * diff --git a/src/jwt/index.ts b/src/jwt/index.ts index f479517936..59f855337a 100644 --- a/src/jwt/index.ts +++ b/src/jwt/index.ts @@ -13,11 +13,8 @@ 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({ - token = {}, - secret, - maxAge = DEFAULT_MAX_AGE, -}: JWTEncodeParams) { +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" }) @@ -28,10 +25,8 @@ export async function encode({ } /** Decodes a NextAuth.js issued JWT. */ -export async function decode({ - token, - secret, -}: JWTDecodeParams): Promise { +export async function decode(params: JWTDecodeParams): Promise { + const { token, secret } = params if (!token) return null const encryptionSecret = await getDerivedEncryptionKey(secret) const { payload } = await jwtDecrypt(token, encryptionSecret, { @@ -55,7 +50,11 @@ export interface GetTokenParams { * @default false */ raw?: R - secret: string + /** + * The same `secret` used in the `NextAuth` configuration. + * Defaults to the `NEXTAUTH_SECRET` environment variable. + */ + secret?: string decode?: JWTOptions["decode"] logger?: LoggerInstance | Console } @@ -78,6 +77,7 @@ export async function getToken( raw, decode: _decode = decode, logger = console, + secret = process.env.NEXTAUTH_SECRET, } = params ?? {} if (!req) throw new Error("Must pass `req` to JWT getToken()") @@ -103,7 +103,7 @@ export async function getToken( try { // @ts-expect-error - return await _decode({ token, ...params }) + return await _decode({ token, secret }) } catch { // @ts-expect-error return null diff --git a/src/jwt/types.ts b/src/jwt/types.ts index f588328a61..ecd0e2a9b0 100644 --- a/src/jwt/types.ts +++ b/src/jwt/types.ts @@ -34,7 +34,11 @@ export interface JWTDecodeParams { } export interface JWTOptions { - /** The secret used to encode/decode the NextAuth.js issued JWT. */ + /** + * The secret used to encode/decode the NextAuth.js issued JWT. + * @deprecated Set the `NEXTAUTH_SECRET` environment vairable or + * use the top-level `secret` option instead + */ secret: string /** * The maximum age of the NextAuth.js issued JWT in seconds. diff --git a/src/next/index.ts b/src/next/index.ts index bc0794adb6..966b948493 100644 --- a/src/next/index.ts +++ b/src/next/index.ts @@ -19,6 +19,10 @@ async function NextAuthNextHandler( options: NextAuthOptions ) { const { nextauth, ...query } = req.query + + options.secret = + options.secret ?? options.jwt?.secret ?? process.env.NEXTAUTH_SECRET + const handler = await NextAuthHandler({ req: { host: detectHost(req.headers["x-forwarded-host"]),