Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support browser extensions #46

Closed
Closed
Changes from 1 commit
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
Next Next commit
add context mode for client
  • Loading branch information
raynirola committed Apr 14, 2024
commit ef4f202e38ef475a08889715e77c0d5deeeda045
22 changes: 12 additions & 10 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ function getAlgoName(num :NumAlgo) :NamedAlgo {
* @param {'discouraged'|'preferred'|'required'} [options.discoverable] A "discoverable" credential can be selected using `authenticate(...)` without providing credential IDs.
* Instead, a native pop-up will appear for user selection.
* This may have an impact on the "passkeys" user experience and syncing behavior of the key.
* @param {'browser'|'extension'} [mode='browser'] Context in which the function is called. If 'extension', the `rpId` will be set to `undefined`.
*/
export async function register(username :string, challenge :string, options? :RegisterOptions) :Promise<RegistrationEncoded> {
export async function register(username :string, challenge :string, options? :RegisterOptions, mode: "browser" | "extension" = "browser") :Promise<RegistrationEncoded> {
options = options ?? {}

if(!utils.isBase64url(challenge))
Expand All @@ -80,7 +81,7 @@ export async function register(username :string, challenge :string, options? :Re
const creationOptions :PublicKeyCredentialCreationOptions = {
challenge: utils.parseBase64url(challenge),
rp: {
id: window.location.hostname,
id: mode === "extension" ? undefined : window.location.hostname,
name: window.location.hostname
},
user: {
Expand All @@ -106,12 +107,12 @@ export async function register(username :string, challenge :string, options? :Re
console.debug(creationOptions)

const credential = await navigator.credentials.create({publicKey: creationOptions}) as any //PublicKeyCredential

if(options.debug)
console.debug(credential)

const response = credential.response as any // AuthenticatorAttestationResponse

let registration :RegistrationEncoded = {
username: username,
credential: {
Expand All @@ -137,7 +138,7 @@ async function getTransports(authType :AuthType) :Promise<AuthenticatorTransport
// 'hybrid' was added mid-2022 in the specs and currently not yet available in the official dom types
// @ts-ignore
const roaming :AuthenticatorTransport[] = ['hybrid', 'usb', 'ble', 'nfc']

if(authType === "local")
return local
if(authType == "roaming" || authType === "extern")
Expand Down Expand Up @@ -166,8 +167,9 @@ async function getTransports(authType :AuthType) :Promise<AuthenticatorTransport
* @param {number} [options.timeout=60000] Number of milliseconds the user has to respond to the biometric/PIN check.
* @param {'required'|'preferred'|'discouraged'} [options.userVerification='required'] Whether to prompt for biometric/PIN check or not.
* @param {'optional'|'conditional'|'required'|'silent'} [options.mediation='optional'] https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get#mediation
* @param {'browser'|'extension'} [mode='browser'] Context in which the function is called. If 'extension', the `rpId` will be set to `undefined`.
*/
export async function authenticate(credentialIds :string[], challenge :string, options? :AuthenticateOptions) :Promise<AuthenticationEncoded> {
export async function authenticate(credentialIds :string[], challenge :string, options? :AuthenticateOptions, mode: "browser" | "extension" = "browser") :Promise<AuthenticationEncoded> {
options = options ?? {}

if(!utils.isBase64url(challenge))
Expand All @@ -177,7 +179,7 @@ export async function authenticate(credentialIds :string[], challenge :string, o

let authOptions :PublicKeyCredentialRequestOptions = {
challenge: utils.parseBase64url(challenge),
rpId: window.location.hostname,
rpId: mode === "extension" ? undefined : window.location.hostname,
allowCredentials: credentialIds.map(id => { return {
id: utils.parseBase64url(id),
type: 'public-key',
Expand All @@ -191,12 +193,12 @@ export async function authenticate(credentialIds :string[], challenge :string, o
console.debug(authOptions)

let auth = await navigator.credentials.get({publicKey: authOptions, mediation: options.mediation}) as PublicKeyCredential

if(options.debug)
console.debug(auth)

const response = auth.response as AuthenticatorAssertionResponse

const authentication :AuthenticationEncoded = {
credentialId: auth.id,
authenticatorData: utils.toBase64url(response.authenticatorData),
Expand Down