Skip to content

Commit d53454b

Browse files
authored
Add onError callback for API errors (#118)
.
1 parent 86fd975 commit d53454b

File tree

4 files changed

+43
-8
lines changed

4 files changed

+43
-8
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@authsignal/browser",
3-
"version": "1.13.1",
3+
"version": "1.14.0",
44
"type": "module",
55
"main": "dist/index.js",
66
"module": "dist/index.js",

src/authsignal.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export class Authsignal {
161161
}
162162

163163
private launchWithPopup(url: string, options: PopupLaunchOptions) {
164-
const {popupOptions} = options;
164+
const {popupOptions, onError} = options;
165165

166166
const popupHandler = new PopupHandler({
167167
width: popupOptions?.width,
@@ -170,13 +170,16 @@ export class Authsignal {
170170
});
171171

172172
const popupUrl = `${url}&mode=popup`;
173+
const expectedOrigin = new URL(url).origin;
173174

174-
popupHandler.show({url: popupUrl});
175+
popupHandler.show({url: popupUrl, expectedOrigin});
175176

176177
return new Promise<TokenPayload>((resolve) => {
177178
let token: string | undefined = undefined;
178179

179180
const onMessage = (event: MessageEvent) => {
181+
if (event.origin !== expectedOrigin) return;
182+
180183
let data: AuthsignalWindowMessageData | null = null;
181184

182185
try {
@@ -185,6 +188,10 @@ export class Authsignal {
185188
// Ignore if the event data is not valid JSON
186189
}
187190

191+
if (data?.event === AuthsignalWindowMessage.AUTHSIGNAL_API_ERROR) {
192+
onError?.({errorCode: data.errorCode, statusCode: data.statusCode});
193+
}
194+
188195
if (data?.event === AuthsignalWindowMessage.AUTHSIGNAL_CLOSE_POPUP) {
189196
token = data.token;
190197

@@ -201,16 +208,19 @@ export class Authsignal {
201208
}
202209

203210
private launchWithWindow(url: string, options: WindowLaunchOptions) {
204-
const {windowOptions} = options;
211+
const {windowOptions, onError} = options;
205212

206213
const windowHandler = new WindowHandler();
207214

208215
const windowUrl = `${url}&mode=popup`;
216+
const expectedOrigin = new URL(url).origin;
209217

210218
windowHandler.show({url: windowUrl, width: windowOptions?.width, height: windowOptions?.height});
211219

212220
return new Promise<TokenPayload>((resolve) => {
213221
const onMessage = (event: MessageEvent) => {
222+
if (event.origin !== expectedOrigin) return;
223+
214224
let data: AuthsignalWindowMessageData | null = null;
215225

216226
try {
@@ -219,6 +229,10 @@ export class Authsignal {
219229
// Ignore if the event data is not valid JSON
220230
}
221231

232+
if (data?.event === AuthsignalWindowMessage.AUTHSIGNAL_API_ERROR) {
233+
onError?.({errorCode: data.errorCode, statusCode: data.statusCode});
234+
}
235+
222236
if (data?.event === AuthsignalWindowMessage.AUTHSIGNAL_CLOSE_POPUP) {
223237
windowHandler.close();
224238
resolve({token: data.token});

src/handlers/popup-handler.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const INITIAL_HEIGHT = "384px";
1212

1313
type PopupShowInput = {
1414
url: string;
15+
expectedOrigin: string;
1516
};
1617

1718
type PopupHandlerOptions = {
@@ -23,6 +24,7 @@ type PopupHandlerOptions = {
2324
export class PopupHandler {
2425
private popup: A11yDialog | null = null;
2526
private height: string | undefined;
27+
private resizeListener: ((event: MessageEvent) => void) | null = null;
2628

2729
constructor({width, height, isClosable}: PopupHandlerOptions) {
2830
if (document.querySelector(`#${CONTAINER_ID}`)) {
@@ -138,10 +140,13 @@ export class PopupHandler {
138140
document.head.removeChild(styleEl);
139141
}
140142

141-
window.removeEventListener("message", resizeIframe);
143+
if (this.resizeListener) {
144+
window.removeEventListener("message", this.resizeListener);
145+
this.resizeListener = null;
146+
}
142147
}
143148

144-
show({url}: PopupShowInput) {
149+
show({url, expectedOrigin}: PopupShowInput) {
145150
if (!this.popup) {
146151
throw new Error("Popup is not initialized");
147152
}
@@ -163,7 +168,12 @@ export class PopupHandler {
163168

164169
// Dynamic resizing if no height is set.
165170
if (!this.height) {
166-
window.addEventListener("message", resizeIframe);
171+
this.resizeListener = (event: MessageEvent) => {
172+
if (event.origin !== expectedOrigin) return;
173+
resizeIframe(event);
174+
};
175+
176+
window.addEventListener("message", this.resizeListener);
167177
}
168178

169179
this.popup?.show();

src/types.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export type PopupLaunchOptions = BaseLaunchOptions & {
2828
*/
2929
isClosable?: boolean;
3030
};
31+
/**
32+
* Called when an API error occurs in the pre-built UI.
33+
*/
34+
onError?: (params: {errorCode?: string; statusCode?: number}) => void;
3135
};
3236

3337
export type WindowLaunchOptions = BaseLaunchOptions & {
@@ -36,6 +40,10 @@ export type WindowLaunchOptions = BaseLaunchOptions & {
3640
width?: number;
3741
height?: number;
3842
};
43+
/**
44+
* Called when an API error occurs in the pre-built UI.
45+
*/
46+
onError?: (params: {errorCode?: string; statusCode?: number}) => void;
3947
};
4048

4149
export type LaunchOptions = RedirectLaunchOptions | PopupLaunchOptions | WindowLaunchOptions;
@@ -64,11 +72,14 @@ export type AuthsignalOptions = {
6472

6573
export enum AuthsignalWindowMessage {
6674
AUTHSIGNAL_CLOSE_POPUP = "AUTHSIGNAL_CLOSE_POPUP",
75+
AUTHSIGNAL_API_ERROR = "AUTHSIGNAL_API_ERROR",
6776
}
6877

6978
export type AuthsignalWindowMessageData = {
7079
event: AuthsignalWindowMessage;
71-
token: string;
80+
token?: string;
81+
errorCode?: string;
82+
statusCode?: number;
7283
};
7384

7485
export type TokenPayload = {

0 commit comments

Comments
 (0)