UNPKG

@auth0/nextjs-auth0

Version:
483 lines (482 loc) 21.7 kB
import { describe, expect, it } from "vitest"; import { getSessionChangesAfterGetAccessToken } from "./session-changes-helpers.js"; function createSessionData(sessionData = {}) { return { user: { sub: "user123", name: "Test User" }, internal: { sid: "session123", createdAt: Date.now() }, tokenSet: { accessToken: "<my_access_token>", expiresAt: Date.now() / 1000 + 3600 }, ...sessionData }; } describe("session-changes-helpers", () => { describe("getSessionChangesAfterGetAccessToken", () => { it("should get the sessionChanges when no scope and audience is provided", () => { const session = createSessionData(); const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200 }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, {})).toEqual({ tokenSet: { accessToken: tokenSet.accessToken, expiresAt: tokenSet.expiresAt, idToken: tokenSet.idToken, refreshToken: tokenSet.refreshToken } }); }); it("should not get any sessionChanges when no scope and audience is provided but no changes", () => { const session = createSessionData(); const tokenSet = { ...session.tokenSet }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, {})).toBeUndefined(); }); it("should get the sessionChanges when scope and audience is provided but are the global values", () => { const session = createSessionData(); const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, requestedScope: "read:messages", scope: "read:messages", audience: "https://api.example.com" }; const globalOptions = { scope: "read:messages", audience: "https://api.example.com" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toEqual({ tokenSet: { accessToken: tokenSet.accessToken, expiresAt: tokenSet.expiresAt, idToken: tokenSet.idToken, refreshToken: tokenSet.refreshToken, // TODO: Do we want to add these to the main tokenSet? requestedScope: "read:messages", scope: "read:messages", audience: "https://api.example.com" } }); }); it("should get the sessionChanges when scope and audience is provided and are not the global values", () => { const session = createSessionData(); const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, scope: "write:messages", audience: "https://api.example.com" }; const globalOptions = { scope: "read:messages", audience: "https://read-api.example.com" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toEqual({ tokenSet: { ...session.tokenSet, idToken: tokenSet.idToken, refreshToken: tokenSet.refreshToken }, accessTokens: [ { accessToken: tokenSet.accessToken, expiresAt: tokenSet.expiresAt, scope: tokenSet.scope, audience: tokenSet.audience } ] }); }); it("should get the sessionChanges when scope and audience is provided, are not the global values and entry already exists", () => { const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, scope: "write:messages", audience: "https://api.example.com" }; const session = createSessionData({ accessTokens: [ { accessToken: "<my_old_access_token>", expiresAt: Date.now() / 1000 + 7200, requestedScope: tokenSet.scope, scope: tokenSet.scope, audience: tokenSet.audience }, { accessToken: "<my_access_token>", expiresAt: Date.now() / 1000 + 7200, requestedScope: "scope-a", scope: "scope-a", audience: "<another_audience>" } ] }); const globalOptions = { scope: "read:messages", audience: "https://read-api.example.com" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toEqual({ tokenSet: { ...session.tokenSet, idToken: tokenSet.idToken, refreshToken: tokenSet.refreshToken }, accessTokens: [ { accessToken: tokenSet.accessToken, expiresAt: tokenSet.expiresAt, scope: tokenSet.scope, requestedScope: tokenSet.scope, audience: tokenSet.audience }, { accessToken: session.accessTokens[1].accessToken, expiresAt: session.accessTokens[1].expiresAt, scope: session.accessTokens[1].scope, requestedScope: session.accessTokens[1].requestedScope, audience: session.accessTokens[1].audience } ] }); }); it("should get the sessionChanges when scope and no audience is provided", () => { const session = createSessionData(); const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, scope: "a", requestedScope: "a" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, {})).toBeUndefined(); }); it("should get the sessionChanges when audience is provided, but no scope is provided and global scope is used", () => { const session = createSessionData(); const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, scope: "default-scope", audience: "https://api.example.com" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, { scope: "default-scope" })).toEqual({ tokenSet: { ...session.tokenSet, idToken: tokenSet.idToken, refreshToken: tokenSet.refreshToken }, accessTokens: [ { accessToken: tokenSet.accessToken, audience: "https://api.example.com", scope: "default-scope", expiresAt: tokenSet.expiresAt } ] }); }); it("should get the sessionChanges when scope and audience is provided and are not the global values and requested scope differ, but provided scope are identical", () => { const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, scope: "a", requestedScope: "a c", audience: "https://api.example.com" }; const globalOptions = { scope: "read:messages", audience: "https://read-api.example.com" }; const accessTokens = [ { accessToken: "<my_access_token_1>", expiresAt: Date.now() / 1000 + 7200, scope: "a", requestedScope: "a b", audience: "https://api.example.com" }, { accessToken: "<my_access_token_2>", expiresAt: Date.now() / 1000 + 7200, scope: "scope-1", audience: "https://api.example.com" } ]; const session = createSessionData({ accessTokens }); expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toEqual({ tokenSet: { ...session.tokenSet, idToken: tokenSet.idToken, refreshToken: tokenSet.refreshToken }, accessTokens: [ { accessToken: tokenSet.accessToken, expiresAt: tokenSet.expiresAt, scope: "a", requestedScope: "a b c", audience: "https://api.example.com" }, accessTokens[1] ] }); }); it("should get the sessionChanges when audience is provided, but no scope is provided and no global scope is available", () => { const session = createSessionData(); const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, audience: "https://api.example.com" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, {})).toEqual({ tokenSet: { ...session.tokenSet, idToken: tokenSet.idToken, refreshToken: tokenSet.refreshToken }, accessTokens: [ { accessToken: tokenSet.accessToken, audience: "https://api.example.com", scope: undefined, expiresAt: tokenSet.expiresAt } ] }); }); it("should get the sessionChanges when scope and audience are not provided but available as global", () => { const session = createSessionData(); const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200 }; const globalOptions = { scope: "read:messages", audience: "https://api.example.com" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toEqual({ tokenSet: { accessToken: tokenSet.accessToken, expiresAt: tokenSet.expiresAt, idToken: tokenSet.idToken, refreshToken: tokenSet.refreshToken } }); }); it("should get the sessionChanges when access token entry found but access token is different", () => { const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, scope: "read:messages write:messages", requestedScope: "read:messages write:messages", audience: "https://api.example.com" }; const globalOptions = { scope: "read:messages", audience: "https://api.example.com" }; const accessTokens = [ { accessToken: "<my_access_token>", scope: "read:messages write:messages", requestedScope: "read:messages write:messages", expiresAt: Date.now() / 1000 + 3600, audience: "https://api.example.com" }, { accessToken: "<my_other_access_token>", scope: "read:projects", requestedScope: "read:projects", expiresAt: Date.now() / 1000 + 3600, audience: "https://api.example.com" } ]; const session = createSessionData({ accessTokens }); expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toEqual({ tokenSet: { accessToken: session.tokenSet.accessToken, expiresAt: session.tokenSet.expiresAt, idToken: tokenSet.idToken, refreshToken: tokenSet.refreshToken }, accessTokens: [ { accessToken: tokenSet.accessToken, scope: tokenSet.scope, requestedScope: tokenSet.requestedScope, expiresAt: tokenSet.expiresAt, audience: "https://api.example.com" }, accessTokens[1] ] }); }); describe("no session changes cases", () => { it("should return undefined when global audience/scope tokenSet has no changes", () => { const expiresAt = Date.now() / 1000 + 3600; const session = createSessionData({ tokenSet: { accessToken: "<my_access_token>", expiresAt, refreshToken: "<my_refresh_token>", idToken: "<my_id_token>" } }); const tokenSet = { accessToken: "<my_access_token>", expiresAt, refreshToken: "<my_refresh_token>", idToken: "<my_id_token>" }; const globalOptions = { scope: "read:messages", audience: "https://api.example.com" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toBeUndefined(); }); it("should return undefined when existing access token is the same", () => { const tokenSet = { accessToken: "<my_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, scope: "write:messages", requestedScope: "write:messages", audience: "https://api.example.com" }; const globalOptions = { scope: "read:messages", audience: "https://read-api.example.com" }; const accessTokens = [ { accessToken: "<my_access_token>", // Same access token scope: "write:messages", requestedScope: "write:messages", expiresAt: Date.now() / 1000 + 3600, audience: "https://api.example.com" } ]; const session = createSessionData({ accessTokens }); expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toBeUndefined(); }); it("should return undefined when there is no audience for specific access token", () => { const session = createSessionData(); const tokenSet = { accessToken: "<my_new_access_token>", idToken: "<my_new_id_token>", refreshToken: "<my_new_refresh_token>", expiresAt: Date.now() / 1000 + 7200, scope: "write:messages", requestedScope: "write:messages" // No audience }; const globalOptions = { scope: "read:messages" // No audience }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toBeUndefined(); }); it("should return undefined when tokenSet matches global scope from session", () => { const expiresAt = Date.now() / 1000 + 3600; const session = createSessionData({ tokenSet: { accessToken: "<my_access_token>", expiresAt, refreshToken: "<my_refresh_token>", scope: "read:messages", requestedScope: "read:messages" } }); const tokenSet = { accessToken: "<my_access_token>", expiresAt, refreshToken: "<my_refresh_token>", scope: "read:messages", requestedScope: "read:messages" }; const globalOptions = { scope: "read:messages" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toBeUndefined(); }); it("should return undefined when access token in accessTokens array is identical", () => { const accessToken = "<my_access_token>"; const expiresAt = Date.now() / 1000 + 7200; const accessTokens = [ { accessToken, scope: "write:messages delete:messages", requestedScope: "write:messages delete:messages", expiresAt, audience: "https://api.example.com" }, { accessToken: "<other_access_token>", scope: "read:projects", requestedScope: "read:projects", expiresAt, audience: "https://other-api.example.com" } ]; const session = createSessionData({ accessTokens }); const tokenSet = { accessToken, // Same token idToken: "<my_id_token>", refreshToken: "<my_refresh_token>", expiresAt, scope: "write:messages delete:messages", requestedScope: "write:messages delete:messages", audience: "https://api.example.com" }; const globalOptions = { scope: "read:messages", audience: "https://global-api.example.com" }; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toBeUndefined(); }); it("should return undefined when no audience and scope provided with no global options", () => { const accessToken = "<my_access_token>"; const expiresAt = Date.now() / 1000 + 3600; const session = createSessionData({ tokenSet: { accessToken, expiresAt, refreshToken: "<my_refresh_token>" } }); const tokenSet = { accessToken, // Same token expiresAt, refreshToken: "<my_refresh_token>" // No idToken, so no changes }; const globalOptions = {}; expect(getSessionChangesAfterGetAccessToken(session, tokenSet, globalOptions)).toBeUndefined(); }); }); }); });