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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@authsignal/browser",
"version": "1.12.0",
"version": "1.12.1",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
Expand Down
36 changes: 27 additions & 9 deletions src/api/passkey-api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import {buildHeaders, handleTokenExpired} from "./helpers";
import {
AddAuthenticatorRequest,
AddAuthenticatorResponse,
AuthenticationOptsRequest,
AuthenticationOptsResponse,
ChallengeRequest,
ChallengeResponse,
ErrorResponse,
PasskeyAuthenticatorResponse,
Expand All @@ -28,16 +30,23 @@ export class PasskeyApiClient {
token,
username,
authenticatorAttachment,
useCookies,
}: {token: string} & RegistrationOptsRequest): Promise<RegistrationOptsResponse | ErrorResponse> {
const body: RegistrationOptsRequest = Boolean(authenticatorAttachment)
? {username, authenticatorAttachment}
: {username};

const response = await fetch(`${this.baseUrl}/client/user-authenticators/passkey/registration-options/web`, {
const url = useCookies
? `${this.baseUrl}/client/user-authenticators/passkey/registration-options/web`
: `${this.baseUrl}/client/user-authenticators/passkey/registration-options`;

const credentials = useCookies ? "include" : "same-origin";

const response = await fetch(url, {
method: "POST",
headers: buildHeaders({token, tenantId: this.tenantId}),
body: JSON.stringify(body),
credentials: "include",
credentials,
});

const responseJson = await response.json();
Expand All @@ -47,12 +56,17 @@ export class PasskeyApiClient {
return responseJson;
}

async authenticationOptions({token}: {token?: string}): Promise<AuthenticationOptsResponse | ErrorResponse> {
async authenticationOptions({
token,
useCookies,
}: {
token?: string;
} & AuthenticationOptsRequest): Promise<AuthenticationOptsResponse | ErrorResponse> {
const response = await fetch(`${this.baseUrl}/client/user-authenticators/passkey/authentication-options`, {
method: "POST",
headers: buildHeaders({token, tenantId: this.tenantId}),
body: JSON.stringify({}),
credentials: "include",
credentials: useCookies ? "include" : "same-origin",
});

const responseJson = await response.json();
Expand Down Expand Up @@ -81,17 +95,20 @@ export class PasskeyApiClient {
token,
registrationCredential,
conditionalCreate,
challengeId,
useCookies,
}: {token: string} & AddAuthenticatorRequest): Promise<AddAuthenticatorResponse | ErrorResponse> {
const body: AddAuthenticatorRequest = {
registrationCredential,
conditionalCreate,
challengeId,
};

const response = await fetch(`${this.baseUrl}/client/user-authenticators/passkey`, {
method: "POST",
headers: buildHeaders({token, tenantId: this.tenantId}),
body: JSON.stringify(body),
credentials: "include",
credentials: useCookies ? "include" : "same-origin",
});

const responseJson = await response.json();
Expand All @@ -105,14 +122,15 @@ export class PasskeyApiClient {
authenticationCredential,
token,
deviceId,
useCookies,
}: {token?: string} & VerifyRequest): Promise<VerifyResponse | ErrorResponse> {
const body: VerifyRequest = {authenticationCredential, deviceId};

const response = await fetch(`${this.baseUrl}/client/verify/passkey`, {
method: "POST",
headers: buildHeaders({token, tenantId: this.tenantId}),
body: JSON.stringify(body),
credentials: "include",
credentials: useCookies ? "include" : "same-origin",
});

const responseJson = await response.json();
Expand All @@ -139,14 +157,14 @@ export class PasskeyApiClient {
return response.json();
}

async challenge(action: string): Promise<ChallengeResponse | ErrorResponse> {
const url = `${this.baseUrl}/client/challenge/web`;
async challenge({action, useCookies}: ChallengeRequest): Promise<ChallengeResponse | ErrorResponse> {
const url = useCookies ? `${this.baseUrl}/client/challenge/web` : `${this.baseUrl}/client/challenge`;

const response = await fetch(url, {
method: "POST",
headers: buildHeaders({tenantId: this.tenantId}),
body: JSON.stringify({action}),
credentials: "include",
credentials: useCookies ? "include" : "same-origin",
});

const responseJson = await response.json();
Expand Down
18 changes: 16 additions & 2 deletions src/api/types/passkey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,29 @@ import {Authenticator} from "./shared";
export type RegistrationOptsRequest = {
username?: string;
authenticatorAttachment?: AuthenticatorAttachment | null;
useCookies?: boolean;
};

export type RegistrationOptsResponse = {
challengeId: string;
challengeId?: string;
options: PublicKeyCredentialCreationOptionsJSON;
};

export type AuthenticationOptsRequest = {
challengeId?: string;
useCookies?: boolean;
};

export type AuthenticationOptsResponse = {
options: PublicKeyCredentialCreationOptionsJSON;
challengeId?: string;
};

export type AddAuthenticatorRequest = {
registrationCredential: RegistrationResponseJSON;
conditionalCreate?: boolean;
challengeId?: string;
useCookies?: boolean;
};

export type AddAuthenticatorResponse = {
Expand All @@ -36,7 +45,7 @@ export type AddAuthenticatorResponse = {
export type VerifyRequest = {
authenticationCredential: AuthenticationResponseJSON;
deviceId?: string;
cookies?: boolean;
useCookies?: boolean;
};

export type VerifyResponse = {
Expand All @@ -53,6 +62,11 @@ export type PasskeyAuthenticatorResponse = {
verifiedAt: string;
};

export type ChallengeRequest = {
action?: string;
useCookies?: boolean;
};

export type ChallengeResponse = {
challengeId: string;
};
Expand Down
19 changes: 14 additions & 5 deletions src/passkey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {TokenCache} from "./token-cache";
import {handleErrorResponse, handleWebAuthnError} from "./helpers";
import {AuthsignalResponse} from "./types";
import {Authenticator} from "./api/types/shared";

type PasskeyOptions = {
baseUrl: string;
tenantId: string;
Expand All @@ -24,6 +25,7 @@ type SignUpParams = {
displayName?: string;
authenticatorAttachment?: AuthenticatorAttachment | null;
useAutoRegister?: boolean;
useCookies?: boolean;
};

type SignUpResponse = {
Expand All @@ -36,7 +38,7 @@ type SignInParams = {
autofill?: boolean;
action?: string;
token?: string;
cookies?: boolean;
useCookies?: boolean;
onVerificationStarted?: () => unknown;
};

Expand Down Expand Up @@ -69,6 +71,7 @@ export class Passkey {
token,
authenticatorAttachment = "platform",
useAutoRegister = false,
useCookies = false,
}: SignUpParams): Promise<AuthsignalResponse<SignUpResponse>> {
const userToken = token ?? this.cache.token;

Expand All @@ -87,6 +90,7 @@ export class Passkey {
displayName,
token: userToken,
authenticatorAttachment,
useCookies,
};

const optionsResponse = await this.api.registrationOptions(optionsInput);
Expand All @@ -102,6 +106,7 @@ export class Passkey {
registrationCredential: registrationResponse,
token: userToken,
conditionalCreate: useAutoRegister,
useCookies,
});

if ("error" in addAuthenticatorResponse) {
Expand Down Expand Up @@ -152,17 +157,20 @@ export class Passkey {
}
}

const challengeResponse = params?.action ? await this.api.challenge(params.action) : null;
const challengeResponse = params?.action
? await this.api.challenge({action: params?.action, useCookies: params?.useCookies})
: null;

if (challengeResponse && "error" in challengeResponse) {
autofillRequestPending = false;

return handleErrorResponse(challengeResponse);
}

const optionsResponse = params?.action
? await this.api.authenticationOptions({token: params?.token})
: await this.api.authenticationOptionsWeb({token: params?.token});
const optionsResponse =
params?.action || !params?.useCookies
? await this.api.authenticationOptions({token: params?.token})
: await this.api.authenticationOptionsWeb({token: params?.token});

if ("error" in optionsResponse) {
autofillRequestPending = false;
Expand All @@ -184,6 +192,7 @@ export class Passkey {
authenticationCredential: authenticationResponse,
token: params?.token,
deviceId: this.anonymousId,
useCookies: params?.useCookies,
});

if ("error" in verifyResponse) {
Expand Down
Loading