Skip to content

Commit 50bf374

Browse files
authored
Merge pull request #2460 from Sune1337/feature/iframe-attributes
Support custom iframe attributes for silent signin
2 parents 9a30d6e + 81563f2 commit 50bf374

6 files changed

Lines changed: 45 additions & 6 deletions

File tree

docs/oidc-client-ts.api.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ export interface IdTokenClaims extends Mandatory<OidcStandardClaims, "sub">, Man
131131

132132
// @public (undocumented)
133133
export interface IFrameWindowParams {
134+
// (undocumented)
135+
iframeAttributes?: Record<string, string>;
134136
// (undocumented)
135137
silentRequestTimeoutInSeconds?: number;
136138
}
@@ -1120,6 +1122,7 @@ export interface UserManagerSettings extends OidcClientSettings {
11201122
accessTokenExpiringNotificationTimeInSeconds?: number;
11211123
automaticSilentRenew?: boolean;
11221124
checkSessionIntervalInSeconds?: number;
1125+
iframeAttributes?: Record<string, string> | undefined;
11231126
iframeNotifyParentOrigin?: string;
11241127
iframeScriptOrigin?: string;
11251128
includeIdTokenInSilentRenew?: boolean;
@@ -1157,6 +1160,8 @@ export class UserManagerSettingsStore extends OidcClientSettingsStore {
11571160
// (undocumented)
11581161
readonly checkSessionIntervalInSeconds: number;
11591162
// (undocumented)
1163+
readonly iframeAttributes?: Record<string, string>;
1164+
// (undocumented)
11601165
readonly iframeNotifyParentOrigin: string | undefined;
11611166
// (undocumented)
11621167
readonly iframeScriptOrigin: string | undefined;

src/UserManager.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export type SigninPopupArgs = PopupWindowParams & ExtraSigninRequestArgs;
4545
/**
4646
* @public
4747
*/
48-
export type ExtraSignInSilentArgs = {
48+
export type ExtraSignInSilentArgs = {
4949
// forceIframeAuth bypasses refresh token usage and forces iframe-based silent authentication
5050
forceIframeAuth?: boolean;
5151
};
@@ -313,6 +313,7 @@ export class UserManager {
313313
const logger = this._logger.create("signinSilent");
314314
const {
315315
silentRequestTimeoutInSeconds,
316+
iframeAttributes,
316317
...requestArgs
317318
} = args;
318319
// first determine if we have a refresh token, or need to use iframe
@@ -346,7 +347,7 @@ export class UserManager {
346347
verifySub = user.profile.sub;
347348
}
348349

349-
const handle = await this._iframeNavigator.prepare({ silentRequestTimeoutInSeconds });
350+
const handle = await this._iframeNavigator.prepare({ silentRequestTimeoutInSeconds, iframeAttributes });
350351
user = await this._signin({
351352
request_type: "si:s",
352353
redirect_uri: url,

src/UserManagerSettings.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const DefaultPopupTarget = "_blank";
1717
const DefaultAccessTokenExpiringNotificationTimeInSeconds = 60;
1818
const DefaultCheckSessionIntervalInSeconds = 2;
1919
export const DefaultSilentRequestTimeoutInSeconds = 10;
20+
export const DefaultIFrameAttributes = undefined;
2021

2122
/**
2223
* The settings used to configure the {@link UserManager}.
@@ -46,6 +47,11 @@ export interface UserManagerSettings extends OidcClientSettings {
4647
/** The script origin to check during 'message' callback execution while performing silent auth via iframe (default: window.location.origin) */
4748
iframeScriptOrigin?: string;
4849

50+
/**
51+
* Defines additional attributes to add to iframe used by silent login.
52+
*/
53+
iframeAttributes?: Record<string, string> | undefined;
54+
4955
/** The URL for the page containing the code handling the silent renew */
5056
silent_redirect_uri?: string;
5157
/** Number of seconds to wait for the silent renew to return before assuming it has failed or timed out (default: 10) */
@@ -112,6 +118,7 @@ export class UserManagerSettingsStore extends OidcClientSettingsStore {
112118

113119
public readonly silent_redirect_uri: string;
114120
public readonly silentRequestTimeoutInSeconds: number;
121+
public readonly iframeAttributes?: Record<string, string>;
115122
public readonly automaticSilentRenew: boolean;
116123
public readonly validateSubOnSilentRenew: boolean;
117124
public readonly includeIdTokenInSilentRenew: boolean;
@@ -142,6 +149,7 @@ export class UserManagerSettingsStore extends OidcClientSettingsStore {
142149

143150
iframeNotifyParentOrigin = args.iframeNotifyParentOrigin,
144151
iframeScriptOrigin = args.iframeScriptOrigin,
152+
iframeAttributes = args.iframeAttributes,
145153

146154
requestTimeoutInSeconds,
147155
silent_redirect_uri = args.redirect_uri,
@@ -178,6 +186,7 @@ export class UserManagerSettingsStore extends OidcClientSettingsStore {
178186

179187
this.iframeNotifyParentOrigin = iframeNotifyParentOrigin;
180188
this.iframeScriptOrigin = iframeScriptOrigin;
189+
this.iframeAttributes = iframeAttributes;
181190

182191
this.silent_redirect_uri = silent_redirect_uri;
183192
this.silentRequestTimeoutInSeconds = silentRequestTimeoutInSeconds || requestTimeoutInSeconds || DefaultSilentRequestTimeoutInSeconds;

src/navigators/IFrameNavigator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ export class IFrameNavigator implements INavigator {
1616

1717
public async prepare({
1818
silentRequestTimeoutInSeconds = this._settings.silentRequestTimeoutInSeconds,
19+
iframeAttributes = this._settings.iframeAttributes,
1920
}: IFrameWindowParams): Promise<IFrameWindow> {
20-
return new IFrameWindow({ silentRequestTimeoutInSeconds });
21+
return new IFrameWindow({ silentRequestTimeoutInSeconds, iframeAttributes });
2122
}
2223

2324
public async callback(url: string): Promise<void> {

src/navigators/IFrameWindow.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ describe("IFrameWindow", () => {
4242
});
4343
});
4444

45+
describe("attributes", () => {
46+
let frameWindow: IFrameWindow;
47+
48+
beforeAll(() => {
49+
frameWindow = new IFrameWindow({ iframeAttributes: { "allow": "local-network-access *", "another_attr": "another_value" } });
50+
});
51+
52+
it("should have custom attributes", () => {
53+
const allow = frameWindow["_frame"]!.getAttribute("allow");
54+
const anotherAttr = frameWindow["_frame"]!.getAttribute("another_attr");
55+
expect(allow).toBe("local-network-access *");
56+
expect(anotherAttr).toBe("another_value");
57+
});
58+
});
59+
4560
describe("close", () => {
4661
let subject: IFrameWindow;
4762
const parentRemoveChild = vi.fn();

src/navigators/IFrameWindow.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import { Logger } from "../utils";
55
import { ErrorTimeout } from "../errors";
66
import type { NavigateParams, NavigateResponse } from "./IWindow";
77
import { AbstractChildWindow } from "./AbstractChildWindow";
8-
import { DefaultSilentRequestTimeoutInSeconds } from "../UserManagerSettings";
8+
import { DefaultIFrameAttributes, DefaultSilentRequestTimeoutInSeconds } from "../UserManagerSettings";
99

1010
/**
1111
* @public
1212
*/
1313
export interface IFrameWindowParams {
1414
silentRequestTimeoutInSeconds?: number;
15+
iframeAttributes?: Record<string, string>;
1516
}
1617

1718
/**
@@ -24,15 +25,16 @@ export class IFrameWindow extends AbstractChildWindow {
2425

2526
public constructor({
2627
silentRequestTimeoutInSeconds = DefaultSilentRequestTimeoutInSeconds,
28+
iframeAttributes = DefaultIFrameAttributes,
2729
}: IFrameWindowParams) {
2830
super();
2931
this._timeoutInSeconds = silentRequestTimeoutInSeconds;
3032

31-
this._frame = IFrameWindow.createHiddenIframe();
33+
this._frame = IFrameWindow.createHiddenIframe(iframeAttributes);
3234
this._window = this._frame.contentWindow;
3335
}
3436

35-
private static createHiddenIframe(): HTMLIFrameElement {
37+
private static createHiddenIframe(iframeAttributes: Record<string, string> | undefined): HTMLIFrameElement {
3638
const iframe = window.document.createElement("iframe");
3739

3840
// shotgun approach
@@ -43,6 +45,12 @@ export class IFrameWindow extends AbstractChildWindow {
4345
iframe.width = "0";
4446
iframe.height = "0";
4547

48+
if (iframeAttributes) {
49+
for (const attr in iframeAttributes) {
50+
iframe.setAttribute(attr, iframeAttributes[attr]);
51+
}
52+
}
53+
4654
window.document.body.appendChild(iframe);
4755
return iframe;
4856
}

0 commit comments

Comments
 (0)