diff --git a/CHANGELOG.md b/CHANGELOG.md index 6af0edb..5a44a7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] - Add support for account recovery and passkey reset +- Make WebAuthn origin configurable ## [1.32.2] - 2023-03-21 - Add support for discoverable passkey login diff --git a/src/main/main.ts b/src/main/main.ts index 3a165a3..b08e45e 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -60,6 +60,7 @@ export interface Config { domain: string language?: string locale?: string + webAuthnOrigin?: string } export type ApiClientConfig = { @@ -135,7 +136,7 @@ export function createClient(creationConfig: Config): Client { checkParam(creationConfig, 'domain') checkParam(creationConfig, 'clientId') - const { domain, clientId, language, locale } = creationConfig + const { domain, clientId, language, locale, webAuthnOrigin } = creationConfig const eventManager = createEventManager() @@ -203,7 +204,7 @@ export function createClient(creationConfig: Config): Client { ) function addNewWebAuthnDevice(accessToken: string, friendlyName?: string) { - return apiClients.then(clients => clients.webAuthn.addNewWebAuthnDevice(accessToken, friendlyName)) + return apiClients.then(clients => clients.webAuthn.addNewWebAuthnDevice(accessToken, friendlyName, webAuthnOrigin)) } function checkSession(options: AuthOptions = {}) { @@ -275,7 +276,10 @@ export function createClient(creationConfig: Config): Client { } function loginWithWebAuthn(params: LoginWithWebAuthnParams) { - return apiClients.then(clients => clients.webAuthn.loginWithWebAuthn(params)) + return apiClients.then(clients => clients.webAuthn.loginWithWebAuthn({ + ...params, + webAuthnOrigin + })) } function logout(params: LogoutParams = {}, revocationParams?: RevocationParams) { @@ -324,7 +328,10 @@ export function createClient(creationConfig: Config): Client { } function resetPasskeys(params: ResetPasskeysParams) { - return apiClients.then(clients => clients.webAuthn.resetPasskeys(params)) + return apiClients.then(clients => clients.webAuthn.resetPasskeys({ + ...params, + webAuthnOrigin + })) } function sendEmailVerification(params: EmailVerificationParams) { @@ -340,7 +347,10 @@ export function createClient(creationConfig: Config): Client { } function signupWithWebAuthn(params: SignupWithWebAuthnParams, auth?: AuthOptions) { - return apiClients.then(clients => clients.webAuthn.signupWithWebAuthn(params, auth)) + return apiClients.then(clients => clients.webAuthn.signupWithWebAuthn({ + ...params, + webAuthnOrigin + }, auth)) } function startMfaEmailRegistration(params: StartMfaEmailRegistrationParams) { diff --git a/src/main/webAuthnClient.ts b/src/main/webAuthnClient.ts index f565b49..0e31358 100644 --- a/src/main/webAuthnClient.ts +++ b/src/main/webAuthnClient.ts @@ -9,13 +9,14 @@ import { EmailLoginWithWebAuthnParams, encodePublicKeyCredentialCreationOptions, encodePublicKeyCredentialRequestOptions, + InternalLoginWithWebAuthnParams, + InternalSignupWithWebAuthnParams, LoginWithWebAuthnParams, PhoneNumberLoginWithWebAuthnParams, publicKeyCredentialType, RegistrationOptions, serializeAuthenticationPublicKeyCredential, serializeRegistrationPublicKeyCredential, - SignupWithWebAuthnParams } from './webAuthnService' import { ApiClientConfig } from './main' import OAuthClient from './oAuthClient' @@ -37,6 +38,8 @@ type SmsResetPasskeysParams = { export type ResetPasskeysParams = EmailResetPasskeysParams | SmsResetPasskeysParams +export type InternalResetPasskeysParams = { webAuthnOrigin?: string } & ResetPasskeysParams + /** * Identity Rest API Client */ @@ -78,10 +81,10 @@ export default class WebAuthnClient { return (credentials as PublicKeyCredential).type === publicKeyCredentialType } - addNewWebAuthnDevice(accessToken: string, friendlyName?: string): Promise { + addNewWebAuthnDevice(accessToken: string, friendlyName?: string, webAuthnOrigin?: string): Promise { if (window.PublicKeyCredential) { const body = { - origin: window.location.origin, + origin: webAuthnOrigin || window.location.origin, friendlyName: friendlyName || window.navigator.platform } @@ -111,11 +114,11 @@ export default class WebAuthnClient { } } - resetPasskeys(params: ResetPasskeysParams): Promise { + resetPasskeys(params: InternalResetPasskeysParams): Promise { if (window.PublicKeyCredential) { const body = { ...params, - origin: window.location.origin, + origin: params.webAuthnOrigin || window.location.origin, friendlyName: params.friendlyName || window.navigator.platform } @@ -155,16 +158,16 @@ export default class WebAuthnClient { return typeof (params as DiscoverableLoginWithWebAuthnParams).conditionalMediation !== 'undefined' } - private buildWebAuthnParams(params: LoginWithWebAuthnParams): Promise { + private buildWebAuthnParams(params: InternalLoginWithWebAuthnParams): Promise { const body = this.isDiscoverable(params) ? { clientId: this.config.clientId, - origin: window.location.origin, + origin: params.webAuthnOrigin || window.location.origin, scope: resolveScope(params.auth, this.config.scope) } : { clientId: this.config.clientId, - origin: window.location.origin, + origin: params.webAuthnOrigin || window.location.origin, scope: resolveScope(params.auth, this.config.scope), email: (params as EmailLoginWithWebAuthnParams).email, phoneNumber: (params as PhoneNumberLoginWithWebAuthnParams).phoneNumber @@ -181,7 +184,7 @@ export default class WebAuthnClient { }) } - loginWithWebAuthn(params: LoginWithWebAuthnParams): Promise { + loginWithWebAuthn(params: InternalLoginWithWebAuthnParams): Promise { if (!window.PublicKeyCredential) { return Promise.reject(new Error('Unsupported WebAuthn API')) } @@ -231,10 +234,10 @@ export default class WebAuthnClient { return this.http.remove(`${this.registrationUrl}/${deviceId}`, { accessToken }) } - signupWithWebAuthn(params: SignupWithWebAuthnParams, auth?: AuthOptions): Promise { + signupWithWebAuthn(params: InternalSignupWithWebAuthnParams, auth?: AuthOptions): Promise { if (window.PublicKeyCredential) { const body = { - origin: window.location.origin, + origin: params.webAuthnOrigin || window.location.origin, clientId: this.config.clientId, friendlyName: params.friendlyName || window.navigator.platform, profile: params.profile, diff --git a/src/main/webAuthnService.ts b/src/main/webAuthnService.ts index 7e6cd52..eabb750 100644 --- a/src/main/webAuthnService.ts +++ b/src/main/webAuthnService.ts @@ -21,6 +21,8 @@ export type LoginWithWebAuthnParams = { auth?: AuthOptions; signal?: AbortSignal | DiscoverableLoginWithWebAuthnParams ) +export type InternalLoginWithWebAuthnParams = LoginWithWebAuthnParams & { webAuthnOrigin?: string } + export type SignupWithWebAuthnParams = { profile: SignupProfileData friendlyName?: string @@ -28,6 +30,8 @@ export type SignupWithWebAuthnParams = { returnToAfterEmailConfirmation?: string } +export type InternalSignupWithWebAuthnParams = SignupWithWebAuthnParams & { webAuthnOrigin?: string } + export type RegistrationOptions = { friendlyName: string options: {