diff --git a/src/server/auth-client.test.ts b/src/server/auth-client.test.ts index f7bfd4288..079e0090c 100644 --- a/src/server/auth-client.test.ts +++ b/src/server/auth-client.test.ts @@ -520,10 +520,10 @@ ca/T0LLtgmbMmxSv/MmzIg== // assert session has been updated const updatedSessionCookie = response.cookies.get("__session"); expect(updatedSessionCookie).toBeDefined(); - const { payload: updatedSessionCookieValue } = await decrypt( + const { payload: updatedSessionCookieValue } = (await decrypt( updatedSessionCookie!.value, secret - ); + )) as jose.JWTDecryptResult; expect(updatedSessionCookieValue).toEqual( expect.objectContaining({ user: { @@ -960,7 +960,14 @@ ca/T0LLtgmbMmxSv/MmzIg== `__txn_${authorizationUrl.searchParams.get("state")}` ); expect(transactionCookie).toBeDefined(); - expect((await decrypt(transactionCookie!.value, secret)).payload).toEqual( + expect( + ( + (await decrypt( + transactionCookie!.value, + secret + )) as jose.JWTDecryptResult + ).payload + ).toEqual( expect.objectContaining({ nonce: authorizationUrl.searchParams.get("nonce"), codeVerifier: expect.any(String), @@ -1164,7 +1171,12 @@ ca/T0LLtgmbMmxSv/MmzIg== ); expect(transactionCookie).toBeDefined(); expect( - (await decrypt(transactionCookie!.value, secret)).payload + ( + (await decrypt( + transactionCookie!.value, + secret + )) as jose.JWTDecryptResult + ).payload ).toEqual( expect.objectContaining({ nonce: authorizationUrl.searchParams.get("nonce"), @@ -1499,7 +1511,14 @@ ca/T0LLtgmbMmxSv/MmzIg== `__txn_${authorizationUrl.searchParams.get("state")}` ); expect(transactionCookie).toBeDefined(); - expect((await decrypt(transactionCookie!.value, secret)).payload).toEqual( + expect( + ( + (await decrypt( + transactionCookie!.value, + secret + )) as jose.JWTDecryptResult + ).payload + ).toEqual( expect.objectContaining({ nonce: authorizationUrl.searchParams.get("nonce"), maxAge: 3600, @@ -1546,7 +1565,14 @@ ca/T0LLtgmbMmxSv/MmzIg== `__txn_${authorizationUrl.searchParams.get("state")}` ); expect(transactionCookie).toBeDefined(); - expect((await decrypt(transactionCookie!.value, secret)).payload).toEqual( + expect( + ( + (await decrypt( + transactionCookie!.value, + secret + )) as jose.JWTDecryptResult + ).payload + ).toEqual( expect.objectContaining({ nonce: authorizationUrl.searchParams.get("nonce"), codeVerifier: expect.any(String), @@ -1592,7 +1618,14 @@ ca/T0LLtgmbMmxSv/MmzIg== `__txn_${authorizationUrl.searchParams.get("state")}` ); expect(transactionCookie).toBeDefined(); - expect((await decrypt(transactionCookie!.value, secret)).payload).toEqual( + expect( + ( + (await decrypt( + transactionCookie!.value, + secret + )) as jose.JWTDecryptResult + ).payload + ).toEqual( expect.objectContaining({ nonce: authorizationUrl.searchParams.get("nonce"), codeVerifier: expect.any(String), @@ -1726,7 +1759,12 @@ ca/T0LLtgmbMmxSv/MmzIg== const state = transactionCookie.name.replace("__txn_", ""); expect(transactionCookie).toBeDefined(); expect( - (await decrypt(transactionCookie!.value, secret)).payload + ( + (await decrypt( + transactionCookie.value, + secret + )) as jose.JWTDecryptResult + ).payload ).toEqual( expect.objectContaining({ nonce: expect.any(String), @@ -1880,7 +1918,12 @@ ca/T0LLtgmbMmxSv/MmzIg== const state = transactionCookie.name.replace("__txn_", ""); expect(transactionCookie).toBeDefined(); expect( - (await decrypt(transactionCookie!.value, secret)).payload + ( + (await decrypt( + transactionCookie.value, + secret + )) as jose.JWTDecryptResult + ).payload ).toEqual( expect.objectContaining({ nonce: expect.any(String), @@ -1962,7 +2005,7 @@ ca/T0LLtgmbMmxSv/MmzIg== const state = transactionCookie.name.replace("__txn_", ""); expect(transactionCookie).toBeDefined(); expect( - (await decrypt(transactionCookie!.value, secret)).payload + (await decrypt(transactionCookie!.value, secret))!.payload ).toEqual( expect.objectContaining({ nonce: expect.any(String), @@ -2554,7 +2597,10 @@ ca/T0LLtgmbMmxSv/MmzIg== // validate the session cookie const sessionCookie = response.cookies.get("__session"); expect(sessionCookie).toBeDefined(); - const { payload: session } = await decrypt(sessionCookie!.value, secret); + const { payload: session } = (await decrypt( + sessionCookie!.value, + secret + )) as jose.JWTDecryptResult; expect(session).toEqual( expect.objectContaining({ user: { @@ -2735,7 +2781,10 @@ ca/T0LLtgmbMmxSv/MmzIg== // validate the session cookie const sessionCookie = response.cookies.get("__session"); expect(sessionCookie).toBeDefined(); - const { payload: session } = await decrypt(sessionCookie!.value, secret); + const { payload: session } = (await decrypt( + sessionCookie!.value, + secret + )) as jose.JWTDecryptResult; expect(session).toEqual( expect.objectContaining({ user: { @@ -3119,10 +3168,10 @@ ca/T0LLtgmbMmxSv/MmzIg== // validate the session cookie const sessionCookie = response.cookies.get("__session"); expect(sessionCookie).toBeDefined(); - const { payload: session } = await decrypt( + const { payload: session } = (await decrypt( sessionCookie!.value, secret - ); + )) as jose.JWTDecryptResult; expect(session).toEqual(expect.objectContaining(expectedSession)); }); @@ -3662,10 +3711,10 @@ ca/T0LLtgmbMmxSv/MmzIg== // validate the session cookie const sessionCookie = response.cookies.get("__session"); expect(sessionCookie).toBeDefined(); - const { payload: session } = await decrypt( + const { payload: session } = (await decrypt( sessionCookie!.value, secret - ); + )) as jose.JWTDecryptResult; expect(session).toEqual( expect.objectContaining({ user: { @@ -3796,10 +3845,10 @@ ca/T0LLtgmbMmxSv/MmzIg== // validate the session cookie const sessionCookie = response.cookies.get("__session"); expect(sessionCookie).toBeDefined(); - const { payload: session } = await decrypt( + const { payload: session } = (await decrypt( sessionCookie!.value, secret - ); + )) as jose.JWTDecryptResult; expect(session).toEqual( expect.objectContaining({ user: { @@ -3900,10 +3949,10 @@ ca/T0LLtgmbMmxSv/MmzIg== // validate that the session cookie has been updated const updatedSessionCookie = response.cookies.get("__session"); - const { payload: updatedSession } = await decrypt( + const { payload: updatedSession } = (await decrypt( updatedSessionCookie!.value, secret - ); + )) as jose.JWTDecryptResult; expect(updatedSession.tokenSet.accessToken).toEqual(newAccessToken); }); diff --git a/src/server/cookies.test.ts b/src/server/cookies.test.ts index 671a5f5db..c025749f1 100644 --- a/src/server/cookies.test.ts +++ b/src/server/cookies.test.ts @@ -1,4 +1,5 @@ import { NextResponse } from "next/server.js"; +import * as jose from "jose"; import { describe, expect, it } from "vitest"; import { generateSecret } from "../test/utils.js"; @@ -13,9 +14,9 @@ describe("encrypt/decrypt", async () => { const maxAge = 60 * 60; // 1 hour in seconds const expiration = Math.floor(Date.now() / 1000 + maxAge); const encrypted = await encrypt(payload, secret, expiration); - const decrypted = await decrypt(encrypted, secret); + const decrypted = await decrypt(encrypted, secret) as jose.JWTDecryptResult; - expect(decrypted.payload).toEqual(expect.objectContaining(payload)); + expect(decrypted!.payload).toEqual(expect.objectContaining(payload)); }); it("should fail to decrypt a payload with the incorrect secret", async () => { @@ -32,9 +33,8 @@ describe("encrypt/decrypt", async () => { const payload = { key: "value" }; const expiration = Math.floor(Date.now() / 1000 - 60); // 60 seconds in the past const encrypted = await encrypt(payload, secret, expiration); - await expect(() => decrypt(encrypted, secret)).rejects.toThrowError( - `"exp" claim timestamp check failed` - ); + const decrypted = await decrypt(encrypted, secret); + expect(decrypted).toBeNull(); }); it("should fail to encrypt if a secret is not provided", async () => { diff --git a/src/server/cookies.ts b/src/server/cookies.ts index 6feac8d10..f734ca0a5 100644 --- a/src/server/cookies.ts +++ b/src/server/cookies.ts @@ -44,20 +44,27 @@ export async function decrypt( secret: string, options?: jose.JWTDecryptOptions ) { - const encryptionSecret = await hkdf( - DIGEST, - secret, - "", - ENCRYPTION_INFO, - BYTE_LENGTH - ); + try { + const encryptionSecret = await hkdf( + DIGEST, + secret, + "", + ENCRYPTION_INFO, + BYTE_LENGTH + ); - const cookie = await jose.jwtDecrypt(cookieValue, encryptionSecret, { - ...options, - ...{ clockTolerance: 15 } - }); + const cookie = await jose.jwtDecrypt(cookieValue, encryptionSecret, { + ...options, + ...{ clockTolerance: 15 } + }); - return cookie; + return cookie; + } catch (e: any) { + if (e.code === "ERR_JWT_EXPIRED") { + return null; + } + throw e; + } } /** diff --git a/src/server/session/stateful-session-store.test.ts b/src/server/session/stateful-session-store.test.ts index 36969c1a7..6f8302cd3 100644 --- a/src/server/session/stateful-session-store.test.ts +++ b/src/server/session/stateful-session-store.test.ts @@ -1,3 +1,4 @@ +import * as jose from "jose"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { generateSecret } from "../../test/utils.js"; @@ -335,7 +336,10 @@ describe("Stateful Session Store", async () => { await sessionStore.set(requestCookies, responseCookies, session); const cookie = responseCookies.get("__session"); - const { payload: cookieValue } = await decrypt(cookie!.value, secret); + const { payload: cookieValue } = (await decrypt( + cookie!.value, + secret + )) as jose.JWTDecryptResult; expect(cookie).toBeDefined(); expect(cookieValue).toHaveProperty("id"); @@ -389,7 +393,10 @@ describe("Stateful Session Store", async () => { await sessionStore.set(requestCookies, responseCookies, session); const cookie = responseCookies.get("__session"); - const { payload: cookieValue } = await decrypt(cookie!.value, secret); + const { payload: cookieValue } = (await decrypt( + cookie!.value, + secret + )) as jose.JWTDecryptResult; expect(cookie).toBeDefined(); expect(cookieValue).toHaveProperty("id"); @@ -437,7 +444,10 @@ describe("Stateful Session Store", async () => { await sessionStore.set(requestCookies, responseCookies, session); const cookie = responseCookies.get("__session"); - const { payload: cookieValue } = await decrypt(cookie!.value, secret); + const { payload: cookieValue } = (await decrypt( + cookie!.value, + secret + )) as jose.JWTDecryptResult; expect(cookie).toBeDefined(); expect(cookieValue).toHaveProperty("id"); @@ -496,7 +506,10 @@ describe("Stateful Session Store", async () => { await sessionStore.set(requestCookies, responseCookies, session, true); const cookie = responseCookies.get("__session"); - const { payload: cookieValue } = await decrypt(cookie!.value, secret); + const { payload: cookieValue } = (await decrypt( + cookie!.value, + secret + )) as jose.JWTDecryptResult; expect(cookie).toBeDefined(); expect(store.delete).toHaveBeenCalledWith(sessionId); // the old session should be deleted @@ -545,7 +558,10 @@ describe("Stateful Session Store", async () => { await sessionStore.set(requestCookies, responseCookies, session); const cookie = responseCookies.get("__session"); - const { payload: cookieValue } = await decrypt(cookie!.value, secret); + const { payload: cookieValue } = (await decrypt( + cookie!.value, + secret + )) as jose.JWTDecryptResult; expect(cookie).toBeDefined(); expect(cookieValue).toHaveProperty("id"); @@ -595,7 +611,10 @@ describe("Stateful Session Store", async () => { await sessionStore.set(requestCookies, responseCookies, session); const cookie = responseCookies.get("__session"); - const { payload: cookieValue } = await decrypt(cookie!.value, secret); + const { payload: cookieValue } = (await decrypt( + cookie!.value, + secret + )) as jose.JWTDecryptResult; expect(cookie).toBeDefined(); expect(cookieValue).toHaveProperty("id"); @@ -689,7 +708,10 @@ describe("Stateful Session Store", async () => { await sessionStore.set(requestCookies, responseCookies, session); const cookie = responseCookies.get("my-session"); - const { payload: cookieValue } = await decrypt(cookie!.value, secret); + const { payload: cookieValue } = (await decrypt( + cookie!.value, + secret + )) as jose.JWTDecryptResult; expect(cookie).toBeDefined(); expect(cookieValue).toHaveProperty("id"); diff --git a/src/server/session/stateful-session-store.ts b/src/server/session/stateful-session-store.ts index 16306c626..64c3dd6ca 100644 --- a/src/server/session/stateful-session-store.ts +++ b/src/server/session/stateful-session-store.ts @@ -72,9 +72,16 @@ export class StatefulSessionStore extends AbstractSessionStore { // this ensures that v3 sessions are respected and can be transparently rolled over to v4+ sessions let sessionId: string | null = null; try { - const { payload: sessionCookie } = - await cookies.decrypt(cookie.value, this.secret); - sessionId = sessionCookie.id; + const sessionCookie = await cookies.decrypt( + cookie.value, + this.secret + ); + + if (sessionCookie === null) { + return null; + } + + sessionId = sessionCookie.payload.id; } catch (e: any) { // the session cookie could not be decrypted, try to verify if it's a legacy session if (e.code === "ERR_JWE_INVALID") { @@ -115,9 +122,12 @@ export class StatefulSessionStore extends AbstractSessionStore { let sessionId = null; const cookieValue = reqCookies.get(this.sessionCookieName)?.value; if (cookieValue) { - const { payload: sessionCookie } = + const sessionCookie = await cookies.decrypt(cookieValue, this.secret); - sessionId = sessionCookie.id; + + if (sessionCookie) { + sessionId = sessionCookie.payload.id; + } } // if this is a new session created by a new login we need to remove the old session @@ -171,11 +181,13 @@ export class StatefulSessionStore extends AbstractSessionStore { return; } - const { payload: session } = await cookies.decrypt( + const session = await cookies.decrypt( cookieValue, this.secret ); - await this.store.delete(session.id); + if (session) { + await this.store.delete(session.payload.id); + } } } diff --git a/src/server/session/stateless-session-store.test.ts b/src/server/session/stateless-session-store.test.ts index d3da8cb79..7c136caed 100644 --- a/src/server/session/stateless-session-store.test.ts +++ b/src/server/session/stateless-session-store.test.ts @@ -1,3 +1,4 @@ +import * as jose from "jose"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { generateSecret } from "../../test/utils.js"; @@ -227,30 +228,98 @@ describe("Stateless Session Store", async () => { internal: { sid: "auth0-sid", createdAt: Math.floor(Date.now() / 1000) - }, - federatedConnectionTokenSets: [ - { - connection: "google-oauth", - accessToken: "google-at-123", - expiresAt: 123456 - } - ] + } + }; + + const googleConnectionTokenSet = { + connection: "google-oauth", + accessToken: "google-at-123", + expiresAt: 123456 }; const maxAge = 60 * 60; // 1 hour in seconds const expiration = Math.floor(Date.now() / 1000 + maxAge); const encryptedCookieValue = await encrypt(session, secret, expiration); + const encryptedGoogleConnectionCookieValue = await encrypt( + googleConnectionTokenSet, + secret, + expiration + ); const headers = new Headers(); - headers.append("cookie", `__session=${encryptedCookieValue}`); + headers.append( + "cookie", + `__session=${encryptedCookieValue};__FC.0=${encryptedGoogleConnectionCookieValue}` + ); const requestCookies = new RequestCookies(headers); const sessionStore = new StatelessSessionStore({ secret }); - expect(await sessionStore.get(requestCookies)).toEqual( - expect.objectContaining(session) + const result = await sessionStore.get(requestCookies); + + expect(result).toEqual(expect.objectContaining(session)); + expect(result?.connectionTokenSets).toEqual([ + expect.objectContaining(googleConnectionTokenSet) + ]); + }); + + it("should return the decrypted session cookie if it exists and exclude a connection when the JWE is expired", async () => { + const secret = await generateSecret(32); + const session: SessionData = { + user: { sub: "user_123" }, + tokenSet: { + accessToken: "at_123", + refreshToken: "rt_123", + expiresAt: 123456 + }, + internal: { + sid: "auth0-sid", + createdAt: Math.floor(Date.now() / 1000) + } + }; + + const googleConnectionTokenSet = { + connection: "google-oauth", + accessToken: "google-at-123", + expiresAt: 123456 + }; + const githubConnectionTokenSet = { + connection: "github", + accessToken: "github-at-123", + expiresAt: 123456 + }; + const maxAge = 60 * 60; // 1 hour in seconds + const expiration = Math.floor(Date.now() / 1000 + maxAge); + const encryptedCookieValue = await encrypt(session, secret, expiration); + const encryptedGoogleConnectionCookieValue = await encrypt( + googleConnectionTokenSet, + secret, + Math.floor(Date.now() / 1000 - 20) + ); // expired + const encryptedGithubConnectionCookieValue = await encrypt( + githubConnectionTokenSet, + secret, + expiration + ); + + const headers = new Headers(); + headers.append( + "cookie", + `__session=${encryptedCookieValue};__FC.0=${encryptedGoogleConnectionCookieValue};__FC.1=${encryptedGithubConnectionCookieValue}` ); + const requestCookies = new RequestCookies(headers); + + const sessionStore = new StatelessSessionStore({ + secret + }); + + const result = await sessionStore.get(requestCookies); + + expect(result).toEqual(expect.objectContaining(session)); + expect(result?.connectionTokenSets).toEqual([ + expect.objectContaining(githubConnectionTokenSet) + ]); }); }); @@ -297,9 +366,10 @@ describe("Stateless Session Store", async () => { const cookie = responseCookies.get("__session"); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( - expect.objectContaining(session) - ); + expect( + ((await decrypt(cookie!.value, secret)) as jose.JWTDecryptResult) + .payload + ).toEqual(expect.objectContaining(session)); expect(cookie?.path).toEqual("/"); expect(cookie?.httpOnly).toEqual(true); expect(cookie?.sameSite).toEqual("lax"); @@ -333,21 +403,16 @@ describe("Stateless Session Store", async () => { inactivityDuration: 1800 }); - vi.setSystemTime(currentTime + 2 * 3600 * 1000); - await sessionStore.set(requestCookies, responseCookies, session); const cookie = responseCookies.get("__session"); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( - expect.objectContaining(session) - ); - expect(cookie?.path).toEqual("/"); - expect(cookie?.httpOnly).toEqual(true); - expect(cookie?.sameSite).toEqual("lax"); - expect(cookie?.maxAge).toEqual(0); - expect(cookie?.secure).toEqual(false); + + vi.setSystemTime(currentTime + 35 * 60 * 1000); + + const decryptedSession = await decrypt(cookie!.value, secret); + expect(decryptedSession).toEqual(null); }); it("should delete the legacy cookie if it exists", async () => { @@ -474,9 +539,10 @@ describe("Stateless Session Store", async () => { const cookie = responseCookies.get("__session"); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( - expect.objectContaining(session) - ); + expect( + ((await decrypt(cookie!.value, secret)) as jose.JWTDecryptResult) + .payload + ).toEqual(expect.objectContaining(session)); expect(cookie?.path).toEqual("/"); expect(cookie?.httpOnly).toEqual(true); expect(cookie?.sameSite).toEqual("lax"); @@ -516,9 +582,10 @@ describe("Stateless Session Store", async () => { const cookie = responseCookies.get("__session"); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( - expect.objectContaining(session) - ); + expect( + ((await decrypt(cookie!.value, secret)) as jose.JWTDecryptResult) + .payload + ).toEqual(expect.objectContaining(session)); expect(cookie?.path).toEqual("/"); expect(cookie?.httpOnly).toEqual(true); expect(cookie?.sameSite).toEqual("lax"); @@ -557,9 +624,10 @@ describe("Stateless Session Store", async () => { const cookie = responseCookies.get("__session"); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( - expect.objectContaining(session) - ); + expect( + ((await decrypt(cookie!.value, secret)) as jose.JWTDecryptResult) + .payload + ).toEqual(expect.objectContaining(session)); expect(cookie?.path).toEqual("/"); expect(cookie?.httpOnly).toEqual(true); expect(cookie?.sameSite).toEqual("strict"); @@ -595,9 +663,10 @@ describe("Stateless Session Store", async () => { const cookie = responseCookies.get("__session"); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( - expect.objectContaining(session) - ); + expect( + ((await decrypt(cookie!.value, secret)) as jose.JWTDecryptResult) + .payload + ).toEqual(expect.objectContaining(session)); expect(cookie?.path).toEqual("/custom-path"); }); @@ -632,9 +701,10 @@ describe("Stateless Session Store", async () => { const cookie = responseCookies.get("custom-session"); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( - expect.objectContaining(session) - ); + expect( + ((await decrypt(cookie!.value, secret)) as jose.JWTDecryptResult) + .payload + ).toEqual(expect.objectContaining(session)); expect(cookie?.path).toEqual("/"); expect(cookie?.httpOnly).toEqual(true); expect(cookie?.sameSite).toEqual("lax"); @@ -705,7 +775,7 @@ describe("Stateless Session Store", async () => { reconstructedValue!, secret ); - const decryptedPayload = decryptedNewSession.payload; + const decryptedPayload = decryptedNewSession!.payload; expect(decryptedPayload).toEqual(expect.objectContaining(sessionToSet)); // set should be called once for setting the new session cookie and once for deleting the legacy cookie diff --git a/src/server/session/stateless-session-store.ts b/src/server/session/stateless-session-store.ts index fe767a7c5..c21ff8d9b 100644 --- a/src/server/session/stateless-session-store.ts +++ b/src/server/session/stateless-session-store.ts @@ -58,25 +58,37 @@ export class StatelessSessionStore extends AbstractSessionStore { SessionData | LegacySessionPayload >(cookieValue, this.secret); + if (!originalSession) { + return null; + } + const normalizedStatelessSession = normalizeStatelessSession(originalSession); // As connection access tokens are stored in seperate cookies, // we need to get all cookies and only use those that are prefixed with `this.connectionTokenSetsCookieName` - const connectionTokenSets = await Promise.all( - this.getConnectionTokenSetsCookies(reqCookies).map((cookie) => - cookies.decrypt(cookie.value, this.secret) - ) + const connectionTokenSetsCookies = this.getConnectionTokenSetsCookies( + reqCookies ); + const connectionTokenSets = []; + for (const cookie of connectionTokenSetsCookies) { + const decryptedCookie = await cookies.decrypt( + cookie.value, + this.secret + ); + + if (decryptedCookie) { + connectionTokenSets.push(decryptedCookie.payload); + } + } + return { ...normalizedStatelessSession, // Ensure that when there are no connection token sets, we omit the property. ...(connectionTokenSets.length ? { - connectionTokenSets: connectionTokenSets.map( - (tokenSet) => tokenSet.payload - ) + connectionTokenSets } : {}) }; diff --git a/src/server/transaction-store.test.ts b/src/server/transaction-store.test.ts index a37e93c40..845862112 100644 --- a/src/server/transaction-store.test.ts +++ b/src/server/transaction-store.test.ts @@ -1,4 +1,5 @@ import * as oauth from "oauth4webapi"; +import * as jose from "jose"; import { describe, expect, it } from "vitest"; import { generateSecret } from "../test/utils.js"; @@ -105,7 +106,7 @@ describe("Transaction Store", async () => { const cookie = responseCookies.get(cookieName); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( + expect((await decrypt(cookie!.value, secret) as jose.JWTDecryptResult).payload).toEqual( expect.objectContaining(transactionState) ); expect(cookie?.path).toEqual("/"); @@ -168,7 +169,7 @@ describe("Transaction Store", async () => { const cookie = responseCookies.get(cookieName); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( + expect((await decrypt(cookie!.value, secret) as jose.JWTDecryptResult).payload).toEqual( expect.objectContaining(transactionState) ); expect(cookie?.path).toEqual("/"); @@ -206,7 +207,7 @@ describe("Transaction Store", async () => { const cookie = responseCookies.get(cookieName); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( + expect((await decrypt(cookie!.value, secret) as jose.JWTDecryptResult).payload).toEqual( expect.objectContaining(transactionState) ); expect(cookie?.path).toEqual("/"); @@ -244,7 +245,7 @@ describe("Transaction Store", async () => { const cookie = responseCookies.get(cookieName); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( + expect((await decrypt(cookie!.value, secret) as jose.JWTDecryptResult).payload).toEqual( expect.objectContaining(transactionState) ); expect(cookie?.path).toEqual("/custom-path"); @@ -278,9 +279,9 @@ describe("Transaction Store", async () => { const cookie = responseCookies.get(cookieName); expect(cookie).toBeDefined(); - expect((await decrypt(cookie!.value, secret)).payload).toEqual( - expect.objectContaining(transactionState) - ); + expect((await decrypt(cookie!.value, secret) as jose.JWTDecryptResult).payload).toEqual(expect.objectContaining( + transactionState + )); expect(cookie?.path).toEqual("/"); expect(cookie?.httpOnly).toEqual(true); expect(cookie?.sameSite).toEqual("lax"); diff --git a/src/testing/generate-session-cookie.test.ts b/src/testing/generate-session-cookie.test.ts index cb853d4c6..078232d20 100644 --- a/src/testing/generate-session-cookie.test.ts +++ b/src/testing/generate-session-cookie.test.ts @@ -1,3 +1,4 @@ +import * as jose from "jose"; import { describe, expect, it } from "vitest"; import { decrypt } from "../server/cookies.js"; @@ -29,7 +30,9 @@ describe("generateSessionCookie", async () => { }; const sessionCookie = await generateSessionCookie(session, config); expect(sessionCookie).toEqual(expect.any(String)); - expect((await decrypt(sessionCookie, secret)).payload).toEqual( + expect( + ((await decrypt(sessionCookie, secret)) as jose.JWTDecryptResult).payload + ).toEqual( expect.objectContaining({ user: { sub: "user_123" @@ -62,7 +65,9 @@ describe("generateSessionCookie", async () => { }; const sessionCookie = await generateSessionCookie(session, config); expect(sessionCookie).toEqual(expect.any(String)); - expect((await decrypt(sessionCookie, secret)).payload).toEqual( + expect( + ((await decrypt(sessionCookie, secret)) as jose.JWTDecryptResult).payload + ).toEqual( expect.objectContaining({ user: { sub: "user_123" @@ -97,7 +102,9 @@ describe("generateSessionCookie", async () => { }; const sessionCookie = await generateSessionCookie(session, config); expect(sessionCookie).toEqual(expect.any(String)); - expect((await decrypt(sessionCookie, secret)).payload).not.toEqual( + expect( + ((await decrypt(sessionCookie, secret)) as jose.JWTDecryptResult).payload + ).not.toEqual( expect.objectContaining({ internal: expect.anything() }) @@ -120,7 +127,9 @@ describe("generateSessionCookie", async () => { }; const sessionCookie = await generateSessionCookie(session, config); expect(sessionCookie).toEqual(expect.any(String)); - expect((await decrypt(sessionCookie, secret)).payload).not.toEqual( + expect( + ((await decrypt(sessionCookie, secret)) as jose.JWTDecryptResult).payload + ).not.toEqual( expect.objectContaining({ internal: expect.anything() })