diff --git a/src/server/auth-client.test.ts b/src/server/auth-client.test.ts index 7d582f94..cc34a009 100644 --- a/src/server/auth-client.test.ts +++ b/src/server/auth-client.test.ts @@ -514,10 +514,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: { @@ -954,7 +954,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), @@ -1158,7 +1165,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"), @@ -1493,7 +1505,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, @@ -1540,7 +1559,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), @@ -1586,7 +1612,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), @@ -1720,7 +1753,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), @@ -1874,7 +1912,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), @@ -1956,7 +1999,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), @@ -2512,7 +2555,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: { @@ -2695,7 +2741,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: { @@ -3081,10 +3130,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)); }); @@ -3545,10 +3594,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: { @@ -3679,10 +3728,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: { @@ -3783,10 +3832,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 8716e1b0..b71748d2 100644 --- a/src/server/cookies.test.ts +++ b/src/server/cookies.test.ts @@ -1,4 +1,5 @@ import { NextResponse } from "next/server"; +import * as jose from "jose"; import { describe, expect, it } from "vitest"; import { generateSecret } from "../test/utils"; @@ -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 6b3ebfd5..7f346b24 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 7acbd47e..90adf4f0 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"; @@ -332,7 +333,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"); @@ -386,7 +390,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"); @@ -434,7 +441,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"); @@ -493,7 +503,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 @@ -542,7 +555,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"); @@ -592,7 +608,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"); @@ -686,7 +705,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 a602bae8..e79bac35 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 2a0fd6a2..c44a9039 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"; @@ -222,30 +223,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) + ]); }); }); @@ -292,9 +361,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"); @@ -328,21 +398,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 () => { @@ -451,9 +516,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"); @@ -493,9 +559,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"); @@ -534,9 +601,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"); @@ -572,9 +640,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"); }); @@ -609,9 +678,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"); @@ -682,7 +752,7 @@ describe("Stateless Session Store", async () => { reconstructedValue!, secret ); - const decryptedPayload = decryptedNewSession.payload; + const decryptedPayload = decryptedNewSession!.payload; expect(decryptedPayload).toEqual(expect.objectContaining(sessionToSet)); expect(deleteSpy).toHaveBeenCalledTimes(legacyCookiesInSetup.length); diff --git a/src/server/session/stateless-session-store.ts b/src/server/session/stateless-session-store.ts index 06b197ce..6e26f3d9 100644 --- a/src/server/session/stateless-session-store.ts +++ b/src/server/session/stateless-session-store.ts @@ -54,25 +54,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 7207c7ee..d5b79e3e 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"; @@ -100,7 +101,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("/"); @@ -163,7 +164,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("/"); @@ -201,7 +202,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("/"); @@ -239,7 +240,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"); @@ -273,9 +274,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 ad413621..60525547 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"; @@ -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() })