@capgo/capacitor-passkey

July 13, 2026 · View on GitHub

Capgo - Instant updates for Capacitor

➡️ Get Instant updates for your App with Capgo

Missing a feature? We’ll build the plugin for you 💪

Passkeys for Capacitor with a browser-style WebAuthn shim.

Why this plugin

Most Capacitor apps already have browser-oriented passkey code based on:

await navigator.credentials.create({ publicKey: registrationOptions });
await navigator.credentials.get({ publicKey: requestOptions });

This plugin keeps that shape in a Capacitor app:

  • It can auto-patch navigator.credentials.create/get for publicKey requests.
  • It forwards the call to native passkey APIs on iOS and Android.
  • It returns browser-like credential objects so existing code can keep working.
  • It can auto-configure the generated iOS and Android host projects during cap sync/update.
  • It also exposes direct JSON-safe methods when your backend already returns WebAuthn JSON.

What it does not do:

  • It does not generate backend challenges for you.
  • It does not remove the need for your website to host apple-app-site-association and assetlinks.json.
  • It does not make Android native passkeys report your website's HTTPS origin to the server. On Android, normal apps use the app origin (android:apk-key-hash:...).

Documentation

The most complete doc is available here: https://capgo.app/docs/plugins/passkey/

Compatibility

Plugin versionCapacitor compatibilityMaintained
v8.*.*v8.*.*
v7.*.*v7.*.*On demand
v6.*.*v6.*.*
v5.*.*v5.*.*

Note: The major version of this plugin follows the major version of Capacitor. Use the version that matches your Capacitor installation.

Install

You can use our AI-Assisted Setup to install the plugin. Add the Capgo skills to your AI tool using the following command:

npx skills add https://github.com/cap-go/capacitor-skills --skill capacitor-plugins

Then use the following prompt:

Use the `capacitor-plugins` skill from `cap-go/capacitor-skills` to install the `@capgo/capacitor-passkey` plugin in my project.

If you prefer Manual Setup, install the plugin by running the following commands and follow the platform-specific instructions below:

bun add @capgo/capacitor-passkey

Browser-Like Setup

  1. Configure the plugin once in capacitor.config.ts or capacitor.config.json.
  2. Import the plugin from the standard package entrypoint.
  3. Call CapacitorPasskey.autoShimWebAuthn() once during app bootstrap.
  4. Keep your existing browser navigator.credentials.create/get code unchanged.

1. Configure capacitor.config.*

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'app.capgo.passkey.example',
  appName: 'My App',
  webDir: 'dist',
  plugins: {
    CapacitorPasskey: {
      origin: 'https://signin.example.com',
      autoShim: true,
      domains: [
        'signin.example.com',
      ],
    },
  },
};

export default config;

Config keys:

  • origin: the primary HTTPS relying-party origin for the app.
  • domains: optional extra relying-party hostnames to wire natively during cap sync/update.
  • autoShim: defaults to true. This only controls the native cap sync/update auto-configuration hook.

Then sync native projects:

bunx cap sync

During cap sync / cap update, the plugin automatically patches the generated host app:

  • iOS: updates the entitlements file and wires CODE_SIGN_ENTITLEMENTS if needed.
  • Android: injects asset_statements metadata and writes a generated string resource.

You do not need to manually edit the host project files every time.

2. Install The Shim During Bootstrap

import { CapacitorPasskey } from '@capgo/capacitor-passkey';

await CapacitorPasskey.autoShimWebAuthn();

That call reads plugins.CapacitorPasskey from the native Capacitor config and installs the WebAuthn shim explicitly.

3. Keep Existing WebAuthn Calls

After that bootstrap call, your browser-style code can stay the same:

const registration = await navigator.credentials.create({
  publicKey: {
    challenge: crypto.getRandomValues(new Uint8Array(32)),
    rp: {
      id: 'signin.example.com',
      name: 'Example Inc',
    },
    user: {
      id: crypto.getRandomValues(new Uint8Array(32)),
      name: 'ada@example.com',
      displayName: 'Ada Lovelace',
    },
    pubKeyCredParams: [
      { type: 'public-key', alg: -7 },
      { type: 'public-key', alg: -257 },
    ],
  },
});

const authentication = await navigator.credentials.get({
  publicKey: {
    challenge: crypto.getRandomValues(new Uint8Array(32)),
    rpId: 'signin.example.com',
  },
});

What The Hook Configures

The plugin hook only patches the native host app files that Capacitor generates.

  • It does not touch your app source code.
  • It does not require you to permanently hand-edit Xcode or Android project files.
  • It does not publish or generate the website association files for you.

Direct JSON-safe API

If your backend already returns PublicKeyCredentialCreationOptionsJSON or PublicKeyCredentialRequestOptionsJSON, you can call the plugin directly:

import { CapacitorPasskey } from '@capgo/capacitor-passkey';

const registration = await CapacitorPasskey.createCredential({
  origin: 'https://signin.example.com',
  publicKey: registrationOptionsFromBackend,
});

const authentication = await CapacitorPasskey.getCredential({
  origin: 'https://signin.example.com',
  publicKey: requestOptionsFromBackend,
});

Website Files You Still Need

Passkeys only work when your app is associated with the same relying-party domain as your website.

iOS Website Association File

Host an apple-app-site-association file on your relying-party domain:

https://signin.example.com/.well-known/apple-app-site-association

Example:

{
  "webcredentials": {
    "apps": [
      "ABCDE12345.app.capgo.passkey.example"
    ]
  }
}

Notes:

  • The file must be served with HTTP 200.
  • Do not add a .json extension.
  • The webcredentials domain must match the relying-party id you use for passkeys.
  • The plugin hook writes the associated domains entitlement for you during cap sync/update.
  • On iOS 17.4 and newer, the plugin uses the browser-style client-data API so the configured HTTPS origin is reflected in clientDataJSON.

Android Website Association File

Host a Digital Asset Links file at:

https://signin.example.com/.well-known/assetlinks.json

Example:

[
  {
    "relation": [
      "delegate_permission/common.handle_all_urls",
      "delegate_permission/common.get_login_creds"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "app.capgo.passkey.example",
      "sha256_cert_fingerprints": [
        "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
      ]
    }
  }
]
  • Use the same domain as your relying-party id.
  • Include every signing certificate fingerprint you need, including debug builds if you test them.
  • The plugin hook writes the asset_statements metadata and generated string resource for you during cap sync/update.
  • Your website still needs to serve the actual assetlinks.json file.

Backend Notes

This plugin preserves the front-end WebAuthn API shape, but native platforms are not identical to a browser backend contract.

  • iOS 17.4+ can encode the HTTPS origin you configure for the shim or direct API.
  • Android Credential Manager does not act like a privileged browser app. The native response origin is tied to the Android app signature (android:apk-key-hash:...), not automatically to your website.
  • With Digital Asset Links configured, Android can still use the same relying party and passkeys as your website. The part that differs is the literal clientDataJSON.origin string.
  • If your server strictly validates clientDataJSON.origin, allow the Android app origin alongside your web origin.
  • Your backend still needs the normal WebAuthn challenge lifecycle and signature verification.

Web Behavior

  • On the web, the plugin forwards to the real browser WebAuthn API.
  • On native Capacitor, the shim returns browser-like credential objects backed by native APIs.
  • Call CapacitorPasskey.autoShimWebAuthn() once during bootstrap before using browser-style WebAuthn calls.
  • Conditional mediation currently returns false.

Example App

The example-app/ folder demonstrates the auto-shim flow:

  • example-app/capacitor.config.json configures the plugin.
  • example-app/src/main.js imports CapacitorPasskey from @capgo/capacitor-passkey.
  • example-app/src/main.js calls CapacitorPasskey.autoShimWebAuthn() during bootstrap.
  • The actual registration and authentication still go through navigator.credentials.create/get.

API

Capacitor Passkey plugin.

Use autoShimWebAuthn() to keep existing navigator.credentials.create/get code working inside a Capacitor app.

shimWebAuthn(...)

shimWebAuthn(options?: ShimWebAuthnOptions | undefined) => void

Install a browser-style WebAuthn shim on top of the native plugin.

The shim patches navigator.credentials.create/get for publicKey requests and returns browser-like credential objects.

Use this when you want to override the auto-loaded config manually.

ParamType
optionsShimWebAuthnOptions

Since: 1.0.0


getConfiguration()

getConfiguration() => Promise<PasskeyRuntimeConfiguration>

Load plugin configuration from the host Capacitor app.

This reads plugins.CapacitorPasskey from capacitor.config.*.

Returns: Promise<PasskeyRuntimeConfiguration>

Since: 1.1.0


autoShimWebAuthn(...)

autoShimWebAuthn(options?: ShimWebAuthnOptions | undefined) => Promise<PasskeyRuntimeConfiguration>

Install the browser-style shim using host app configuration.

This is the easiest way to keep existing browser WebAuthn code working: configure the plugin in capacitor.config.*, then call this once during app bootstrap.

ParamType
optionsShimWebAuthnOptions

Returns: Promise<PasskeyRuntimeConfiguration>

Since: 1.1.0


createCredential(...)

createCredential(options: CreateCredentialOptions) => Promise<PasskeyRegistrationCredential>

Register a passkey from a JSON-safe WebAuthn request.

This method is useful when your backend already returns the PublicKeyCredentialCreationOptionsJSON form.

ParamType
optionsCreateCredentialOptions

Returns: Promise<PasskeyRegistrationCredential>

Since: 1.0.0


getCredential(...)

getCredential(options: GetCredentialOptions) => Promise<PasskeyAuthenticationCredential>

Authenticate with an existing passkey from a JSON-safe WebAuthn request.

This method is useful when your backend already returns the PublicKeyCredentialRequestOptionsJSON form.

ParamType
optionsGetCredentialOptions

Returns: Promise<PasskeyAuthenticationCredential>

Since: 1.0.0


isSupported()

isSupported() => Promise<PasskeySupportResult>

Report whether passkeys are available in the current runtime.

Returns: Promise<PasskeySupportResult>

Since: 1.0.0


getPluginVersion()

getPluginVersion() => Promise<PluginVersionResult>

Returns the current platform implementation version marker.

Returns: Promise<PluginVersionResult>

Since: 1.0.0


Interfaces

ShimWebAuthnOptions

Options used when installing the browser-style shim.

PropTypeDescription
originstringOptional HTTPS origin to encode into iOS 17.4+ clientDataJSON. Use this when your Capacitor app runs from capacitor://localhost but your relying party expects https://signin.example.com.
forcebooleanForce the shim even if the runtime already exposes navigator.credentials. Defaults to false.

PasskeyRuntimeConfiguration

Runtime configuration loaded from the host app's Capacitor config.

This is the shape returned by getConfiguration().

PropTypeDescription
autoShimbooleanWhether the native cap sync/update hook should wire host projects automatically. Defaults to true.
originstringOptional HTTPS origin used by the config-driven shim install. On iOS 17.4+ this origin is encoded into clientDataJSON.
domainsstring[]Domains associated with the app for passkey usage. These come from domains in Capacitor config plus the hostname derived from origin when available.
platform'ios' | 'android' | 'web'Current runtime platform.

PasskeyRegistrationCredential

JSON-safe registration credential returned by the plugin.

PropTypeDescription
idstringBase64url-encoded credential identifier.
rawIdstringBase64url-encoded raw credential identifier.
typePasskeyCredentialTypeCredential type. Always public-key.
authenticatorAttachmentPasskeyAuthenticatorAttachmentOptional authenticator attachment reported by the platform.
clientExtensionResultsRecord<string, unknown>Client extension results returned by the platform.
responsePasskeyAuthenticatorAttestationResponseJSONRegistration response payload.

PasskeyAuthenticatorAttestationResponseJSON

JSON-safe attestation response payload.

All binary fields are base64url encoded.

PropTypeDescription
clientDataJSONstringBase64url-encoded clientDataJSON.
attestationObjectstringBase64url-encoded attestation object.
publicKeystringOptional base64url-encoded public key when provided by the platform.
publicKeyAlgorithmnumberOptional public key algorithm when provided by the platform.
transportsstring[]Optional transport list when provided by the platform.
authenticatorDatastringOptional base64url-encoded authenticator data.

CreateCredentialOptions

Direct registration request for the plugin transport.

PropTypeDescription
publicKeyPasskeyPublicKeyCredentialCreationOptionsJSONJSON-safe registration request.
originstringOptional HTTPS origin to use for iOS 17.4+ browser-style clientDataJSON.

PasskeyPublicKeyCredentialCreationOptionsJSON

JSON-safe registration request options.

All binary fields must be base64url encoded.

PropTypeDescription
challengestringBase64url-encoded challenge.
rpPasskeyRelyingPartyRelying party information.
userPasskeyUserEntityUser information.
pubKeyCredParamsPasskeyCredentialParameter[]Supported credential algorithms.
timeoutnumberOptional timeout hint in milliseconds.
excludeCredentialsPasskeyCredentialDescriptor[]Optional credentials that must be excluded during registration.
authenticatorSelectionPasskeyAuthenticatorSelectionOptional authenticator preferences.
attestationPasskeyAttestationOptional attestation preference.
hintsstring[]Optional hints copied from the JSON form used by modern WebAuthn toolkits.
extensionsRecord<string, unknown>Optional extensions copied as-is into the request JSON.

PasskeyRelyingParty

JSON-safe relying party information.

PropTypeDescription
idstringRelying party identifier. If omitted, the shim derives it from the configured origin when possible.
namestringHuman-readable relying party name.

PasskeyUserEntity

JSON-safe WebAuthn user entity.

Binary identifiers must be base64url encoded.

PropTypeDescription
idstringBase64url-encoded user handle.
namestringUser name shown by the authenticator.
displayNamestringOptional display name shown by the authenticator.

PasskeyCredentialParameter

JSON-safe credential parameter entry.

PropTypeDescription
typePasskeyCredentialTypeCredential type. Only public-key is supported.
algnumberCOSE algorithm identifier.

PasskeyCredentialDescriptor

JSON-safe representation of a public key credential descriptor.

Binary identifiers must be base64url encoded.

PropTypeDescription
idstringBase64url-encoded credential identifier.
typePasskeyCredentialTypeCredential type. Only public-key is supported.
transportsstring[]Optional transport hints copied from WebAuthn.

PasskeyAuthenticatorSelection

JSON-safe authenticator selection options.

PropTypeDescription
authenticatorAttachmentPasskeyAuthenticatorAttachmentOptional authenticator attachment hint.
residentKeyPasskeyResidentKeyOptional resident key preference.
requireResidentKeybooleanLegacy resident key requirement flag.
userVerificationPasskeyUserVerificationOptional user verification preference.

PasskeyAuthenticationCredential

JSON-safe authentication credential returned by the plugin.

PropTypeDescription
idstringBase64url-encoded credential identifier.
rawIdstringBase64url-encoded raw credential identifier.
typePasskeyCredentialTypeCredential type. Always public-key.
authenticatorAttachmentPasskeyAuthenticatorAttachmentOptional authenticator attachment reported by the platform.
clientExtensionResultsRecord<string, unknown>Client extension results returned by the platform.
responsePasskeyAuthenticatorAssertionResponseJSONAssertion response payload.

PasskeyAuthenticatorAssertionResponseJSON

JSON-safe assertion response payload.

All binary fields are base64url encoded.

PropTypeDescription
clientDataJSONstringBase64url-encoded clientDataJSON.
authenticatorDatastringBase64url-encoded authenticator data.
signaturestringBase64url-encoded signature.
userHandlestring | nullOptional base64url-encoded user handle.

GetCredentialOptions

Direct authentication request for the plugin transport.

PropTypeDescription
publicKeyPasskeyPublicKeyCredentialRequestOptionsJSONJSON-safe authentication request.
mediationstringOptional mediation hint. conditional currently falls back to an explicit prompt.
originstringOptional HTTPS origin to use for iOS 17.4+ browser-style clientDataJSON.
preferImmediatelyAvailableCredentialsbooleanPrefer passkeys stored on the local device, skipping the hybrid/nearby-device picker. Fails with NotAllowedError when no local credential exists. Ignored on web and iOS 15.

PasskeyPublicKeyCredentialRequestOptionsJSON

JSON-safe authentication request options.

All binary fields must be base64url encoded.

PropTypeDescription
challengestringBase64url-encoded challenge.
timeoutnumberOptional timeout hint in milliseconds.
rpIdstringOptional relying party identifier. If omitted, the shim derives it from the configured origin when possible.
allowCredentialsPasskeyCredentialDescriptor[]Optional allow list copied from WebAuthn.
userVerificationPasskeyUserVerificationOptional user verification preference.
hintsstring[]Optional hints copied from the JSON form used by modern WebAuthn toolkits.
extensionsRecord<string, unknown>Optional extensions copied as-is into the request JSON.

PasskeySupportResult

Passkey support status for the current runtime.

PropTypeDescription
availablebooleanWhether passkeys are available on the current runtime.
conditionalMediationbooleanWhether conditional mediation is available.
platform'ios' | 'android' | 'web'Current platform identifier.

PluginVersionResult

Plugin version payload.

PropTypeDescription
versionstringVersion identifier reported by the current platform implementation.

Type Aliases

PasskeyCredentialType

Supported WebAuthn credential type.

'public-key'

PasskeyAuthenticatorAttachment

Supported authenticator attachment values.

'platform' | 'cross-platform'

Record

Construct a type with a set of properties K of type T

{ [P in K]: T; }

PasskeyResidentKey

Supported resident key preferences.

'discouraged' | 'preferred' | 'required'

PasskeyUserVerification

Supported user verification preferences.

'discouraged' | 'preferred' | 'required'

PasskeyAttestation

Supported attestation preferences.

'none' | 'indirect' | 'direct' | 'enterprise'