Skip to main content

Overview

Passkeys enable passwordless authentication using biometric sensors (such as fingerprints or facial recognition), PINs, or patterns. Built on WebAuthn standards, passkeys provide a more secure and user-friendly alternative to traditional passwords by leveraging public key cryptography. Unlike passwords, passkeys are resistant to phishing, cannot be reused across sites, and never leave the user’s device.

Compatibility

Passkey authentication is supported on modern browsers and devices that support WebAuthn. Check browser compatibility for optimal user experience across desktop and mobile devices.
Passkey SDK methods are available via the Passkey extension of the Web client-side SDK.

Use Cases

  • Passwordless authentication using device biometrics (fingerprint, Face ID)
  • Secure multi-device authentication with synced passkeys
  • Simplified login flow without remembering passwords
  • Enhanced security with phishing-resistant authentication

Usage

Installation

Passkey login works as an extension to Magic SDK. To add Passkey authentication to your Magic integration, start by installing the Passkey Extension:
npm install magic-sdk @magic-ext/passkey

Initialization

Create your Magic SDK instance with the Passkey extension:
JavaScript
import { Magic } from 'magic-sdk';
import { PasskeyExtension } from '@magic-ext/passkey';

const magic = new Magic('YOUR_API_KEY', {
  extensions: [new PasskeyExtension()],
});

Register new users

Register new users with the registerNewUser function in the passkey extension. You can optionally provide a username and nickname:
  • username: Used as a display name in the user’s password manager or authenticator
  • nickname: Stored by Magic to help identify the passkey among other registered passkeys
JavaScript
try {
  const result = await magic.passkey.registerNewUser({
    username: '[email protected]',
    nickname: 'My Laptop'
  });

  // Access the DID token
  const idToken = result.idToken;

  // Access device information
  console.log('Device ID:', result.deviceInfo.id);
  console.log('Device nickname:', result.deviceInfo.nickname);
} catch (e) {
  // Handle errors if required!
  console.error('Registration failed:', e);
}

Authenticate users

Authenticate users with the login method in the passkey extension. The browser will prompt the user to select and verify their passkey. Pass showMfaModal: false if you want to handle TOTP MFA verification yourself rather than using Magic’s hosted UI. This is only relevant when users have TOTP MFA enabled alongside passkey login.
JavaScript
try {
  const result = await magic.passkey.login({ username: '[email protected]' });

  // Access the DID token
  const idToken = result.idToken;

  // Access device information
  console.log('Logged in with device:', result.deviceInfo.nickname);
} catch (e) {
  // Handle errors if required!
  console.error('Login failed:', e);
}

TOTP MFA event handling (showMfaModal: false)

When a passkey user also has TOTP MFA enabled, set showMfaModal: false to handle the MFA step with your own UI. Use the event handle to listen for and respond to MFA prompts:
JavaScript
import {
  Magic,
  PasskeyMFAEventEmit,
  PasskeyMFAEventOnReceived,
} from 'magic-sdk';
import { PasskeyExtension } from '@magic-ext/passkey';

const magic = new Magic('YOUR_API_KEY', {
  extensions: [new PasskeyExtension()],
});

const handle = magic.passkey.login({ username: '[email protected]', showMfaModal: false });

handle
  // User has TOTP MFA — prompt for the authenticator code
  .on(PasskeyMFAEventOnReceived.MfaSentHandle, () => {
    const totp = window.prompt('Enter your authenticator code');
    handle.emit(PasskeyMFAEventEmit.VerifyMFACode, totp);
  })
  .on(PasskeyMFAEventOnReceived.InvalidMfaOtp, () => {
    // Invalid code — retry or cancel
    // To trigger the recovery code flow instead: handle.emit(PasskeyMFAEventEmit.LostDevice)
    handle.emit(PasskeyMFAEventEmit.Cancel);
  })
  // Recovery code flow (triggered after emitting LostDevice)
  .on(PasskeyMFAEventOnReceived.RecoveryCodeSentHandle, () => {
    const code = window.prompt('Enter your recovery code');
    handle.emit(PasskeyMFAEventEmit.VerifyRecoveryCode, code);
  })
  .on(PasskeyMFAEventOnReceived.InvalidRecoveryCode, () => {
    handle.emit(PasskeyMFAEventEmit.Cancel);
  })
  .on('done', () => {
    console.log('Login complete');
  })
  .on('error', (err) => {
    console.error(err);
  });

await handle;
Event reference
EventDirectionDescription
PasskeyMFAEventOnReceived.MfaSentHandleReceivedTOTP MFA verification required
PasskeyMFAEventEmit.VerifyMFACodeEmitSend the TOTP code for verification
PasskeyMFAEventOnReceived.InvalidMfaOtpReceivedThe TOTP code was invalid
PasskeyMFAEventEmit.LostDeviceEmitSignal lost authenticator — initiates recovery code flow
PasskeyMFAEventOnReceived.RecoveryCodeSentHandleReceivedRecovery code input is required
PasskeyMFAEventEmit.VerifyRecoveryCodeEmitSend the recovery code for verification
PasskeyMFAEventOnReceived.InvalidRecoveryCodeReceivedThe recovery code was invalid
PasskeyMFAEventEmit.CancelEmitCancel the login request

Return Type

The registerNewUser and login methods return a PasskeyResult object:
TypeScript
interface PasskeyResult {
  idToken: string;
  deviceInfo: {
    id: string;
    nickname: string;
    transport: string;
    userAgent: string;
  };
}

Get User Metadata

Retrieve passkey-specific metadata with the getMetadata method in the passkey extension. The response includes information about all devices registered for the current user:
JavaScript
try {
  const metadata = await magic.passkey.getMetadata();

  /* passkey metadata shape
     {
       "devicesInfo": [
         {
           "id": "device-id-string",
           "nickname": "My Laptop",
           "transport": "internal",
           "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."
         },
         {
           "id": "another-device-id",
           "nickname": "My Phone",
           "transport": "hybrid",
           "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0)..."
         }
       ]
     }
  */

  // List all registered devices
  metadata.devicesInfo.forEach(device => {
    console.log(`Device: ${device.nickname} (${device.transport})`);
  });
} catch (e) {
  // Handle errors if required!
  console.error('Failed to retrieve metadata:', e);
}

Add a passkey

Add a new passkey to an existing user’s account with addPasskey. The user must have an active session. This is useful for registering additional devices — for example, letting a user who originally signed up on desktop also register their phone.
JavaScript
try {
  const result = await magic.passkey.addPasskey({
    username: '[email protected]',
    nickname: 'My Phone',
  });

  console.log('New passkey registered:', result.deviceInfo.id);
} catch (e) {
  console.error('Failed to add passkey:', e);
}
Arguments
ParameterTypeRequiredDescription
usernamestringNoDisplay name shown in the browser’s passkey picker
nicknamestringNoLabel stored by Magic to identify this passkey

Update a passkey

Update a passkey’s nickname with updatePasskey. Use getMetadata to retrieve the id of the passkey you want to update.
JavaScript
try {
  await magic.passkey.updatePasskey({
    passkeyId: 'device-id-string',
    nickname: 'Work Laptop',
  });

  console.log('Passkey updated');
} catch (e) {
  console.error('Failed to update passkey:', e);
}
Arguments
ParameterTypeRequiredDescription
passkeyIdstringYesThe id of the passkey to update, from getMetadata
nicknamestringYesThe new label for this passkey

Remove a passkey

Remove a passkey from the user’s account with removePasskey. Use getMetadata to retrieve the id of the passkey you want to remove.
JavaScript
try {
  await magic.passkey.removePasskey({ passkeyId: 'device-id-string' });

  console.log('Passkey removed');
} catch (e) {
  console.error('Failed to remove passkey:', e);
}
Arguments
ParameterTypeRequiredDescription
passkeyIdstringYesThe id of the passkey to remove, from getMetadata
Removing a passkey that is the user’s only registered passkey while Passkey MFA is enabled will prevent them from completing login. Disable passkey MFA before removing the last passkey.