Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/oidc-client-ts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -969,12 +969,13 @@ export class User {
expires_at?: number;
userState?: unknown;
url_state?: string;
});
}, extraTokenResponseKeys?: string[]);
access_token: string;
get expired(): boolean | undefined;
expires_at?: number;
get expires_in(): number | undefined;
set expires_in(value: number | undefined);
extraTokenResponseProperties?: Record<string, unknown>;
// (undocumented)
static fromStorageString(storageString: string): User;
id_token?: string;
Expand Down Expand Up @@ -1122,6 +1123,7 @@ export interface UserManagerSettings extends OidcClientSettings {
accessTokenExpiringNotificationTimeInSeconds?: number;
automaticSilentRenew?: boolean;
checkSessionIntervalInSeconds?: number;
extraTokenResponseKeys?: string[];
iframeAttributes?: Record<string, string> | undefined;
iframeNotifyParentOrigin?: string;
iframeScriptOrigin?: string;
Expand Down Expand Up @@ -1160,6 +1162,8 @@ export class UserManagerSettingsStore extends OidcClientSettingsStore {
// (undocumented)
readonly checkSessionIntervalInSeconds: number;
// (undocumented)
readonly extraTokenResponseKeys: string[];
// (undocumented)
readonly iframeAttributes?: Record<string, string>;
// (undocumented)
readonly iframeNotifyParentOrigin: string | undefined;
Expand Down
57 changes: 56 additions & 1 deletion src/User.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { User } from "./User";
import { Timer } from "./utils";

describe("User", () => {

let now: number;

beforeEach(() => {
Expand Down Expand Up @@ -46,4 +45,60 @@ describe("User", () => {
expect(subject.scopes).toEqual(["foo", "bar", "baz"]);
});
});

describe("extraTokenResponseProperties", () => {
it("should not provide extraTokenResponseProperties if extraTokenResponseKeys is not provided", () => {
// arrange
const args = {
access_token: "notAToken",
id_token: "not",
patient: "12345", // extra
token_type: "Bearer",
extra1: 0, // extra
extra2: null,
extra3: true,
};

// act
const subject = new User(args as never);

// assert
expect(subject.extraTokenResponseProperties).not.toBeDefined();
});

it("should provide extraTokenResponseProperties if extraTokenResponseKeys is provided", () => {
// arrange
const args = {
access_token: "access_token",
id_token: "id_token",
patient: "12345", // extra
token_type: "Bearer",
extra1: 0, // extra
extra2: null,
extra3: true, // extra but not specified
};

// act
const subject = new User(args as never, [
"patient",
"extra1",
"extra2",
]);

// assert
expect(subject.extraTokenResponseProperties).toBeDefined();
const actualTokenProps = subject.extraTokenResponseProperties ?? {};
const patient = actualTokenProps["patient"];
expect(patient).toBeDefined();
expect(patient).toEqual(args.patient);
const extra1 = actualTokenProps["extra1"];
expect(extra1).toBeDefined();
expect(extra1).toEqual(args.extra1);
const extra2 = actualTokenProps["extra2"];
expect(extra2).toBeDefined();
expect(extra2).toEqual(args.extra2);
const extra3 = actualTokenProps["extra3"];
expect(extra3).not.toBeDefined();
});
});
});
18 changes: 17 additions & 1 deletion src/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ export class User {
/** The expires at returned from the OIDC provider. */
public expires_at?: number;

/**
* The additional token response properties the user has requested to keep via settings.
* @see {@link UserManagerSettings.extraTokenResponseKeys}
*/
public extraTokenResponseProperties?: Record<string, unknown>;

/** custom state data set during the initial signin request */
public readonly state: unknown;
public readonly url_state?: string;
Expand All @@ -64,7 +70,7 @@ export class User {
expires_at?: number;
userState?: unknown;
url_state?: string;
}) {
}, extraTokenResponseKeys?: string[]) {
this.id_token = args.id_token;
this.session_state = args.session_state ?? null;
this.access_token = args.access_token;
Expand All @@ -76,6 +82,16 @@ export class User {
this.expires_at = args.expires_at;
this.state = args.userState;
this.url_state = args.url_state;

if (extraTokenResponseKeys?.length) {
this.extraTokenResponseProperties = {};
for (const key of extraTokenResponseKeys) {
const extraProperty = (args as Record<string, unknown>)[key];
if (extraProperty !== undefined) {
this.extraTokenResponseProperties[key] = extraProperty;
}
}
}
}

/** Computed number of seconds the access token has remaining. */
Expand Down
4 changes: 2 additions & 2 deletions src/UserManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ export class UserManager {
timeoutInSeconds: this.settings.silentRequestTimeoutInSeconds,
...args,
});
const user = new User({ ...args.state, ...response });
const user = new User({ ...args.state, ...response }, this.settings.extraTokenResponseKeys);

await this.storeUser(user);
await this._events.load(user);
Expand Down Expand Up @@ -548,7 +548,7 @@ export class UserManager {

protected async _buildUser(signinResponse: SigninResponse, verifySub?: string) {
const logger = this._logger.create("_buildUser");
const user = new User(signinResponse);
const user = new User(signinResponse, this.settings.extraTokenResponseKeys);
Comment thread
pamapa marked this conversation as resolved.
if (verifySub) {
if (verifySub !== user.profile.sub) {
logger.debug("current user does not match user returned from signin. sub from signin:", user.profile.sub);
Expand Down
20 changes: 20 additions & 0 deletions src/UserManagerSettings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,4 +421,24 @@ describe("UserManagerSettings", () => {
expect(subject.silentRequestTimeoutInSeconds).toEqual(10);
});
});

describe("extraTokenResponseKeys", () => {
it("should return value from the initial settings", () => {
const subject = new UserManagerSettingsStore({
authority: "authority",
client_id: "client",
redirect_uri: "redirect",
extraTokenResponseKeys: ["testProp"],
});
expect(subject.extraTokenResponseKeys).toEqual(["testProp"]);
});
it("should return the default value", () => {
const subject = new UserManagerSettingsStore({
authority: "authority",
client_id: "client",
redirect_uri: "redirect",
});
expect(subject.extraTokenResponseKeys).toEqual([]);
});
});
});
14 changes: 13 additions & 1 deletion src/UserManagerSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ export interface UserManagerSettings extends OidcClientSettings {
*/
maxSilentRenewTimeoutRetries?: number;

/**
* By default the user object only preserves the standard properties
* (access_token, session_state, id_token, refresh_token, token_type, scope, profile, and expiration).
* Any additional properties returned by the OIDC/OAuth2 token response will be ignored unless explicitly listed here. (default: [])
*/
extraTokenResponseKeys?: string[];

/**
* Storage object used to persist User for currently authenticated user (default: window.sessionStorage, InMemoryWebStorage iff no window).
* E.g. `userStore: new WebStorageStateStore({ store: window.localStorage })`
Expand Down Expand Up @@ -136,6 +143,8 @@ export class UserManagerSettingsStore extends OidcClientSettingsStore {
public readonly accessTokenExpiringNotificationTimeInSeconds: number;
public readonly maxSilentRenewTimeoutRetries?: number;

public readonly extraTokenResponseKeys: string[];

public readonly userStore: StateStore;

public constructor(args: UserManagerSettings) {
Expand Down Expand Up @@ -169,9 +178,10 @@ export class UserManagerSettingsStore extends OidcClientSettingsStore {
includeIdTokenInSilentSignout = false,

accessTokenExpiringNotificationTimeInSeconds = DefaultAccessTokenExpiringNotificationTimeInSeconds,

maxSilentRenewTimeoutRetries,

extraTokenResponseKeys = [],

userStore,
} = args;

Expand Down Expand Up @@ -207,6 +217,8 @@ export class UserManagerSettingsStore extends OidcClientSettingsStore {
this.accessTokenExpiringNotificationTimeInSeconds = accessTokenExpiringNotificationTimeInSeconds;
this.maxSilentRenewTimeoutRetries = maxSilentRenewTimeoutRetries;

this.extraTokenResponseKeys = extraTokenResponseKeys;

if (userStore) {
this.userStore = userStore;
}
Expand Down
Loading