Skip to main content

Integrating PasskeyID

📦 Since v25.10.0

This section walks through integrating PasskeyID into your application, including configuring secure webhook-based identity verification and initiating the PasskeyID sequence through the LoginID MFA SDK.

Depending on your architecture, you can either use a supported identity provider or handle identity verification directly within your backend.

Prerequisites​

  • Create an application to obtain a base URL. The SDK uses this base URL to interact with the LoginID authentication service.
  • Create an API key with at least the external-verify scope. You’ll need this to request authorization tokens from your backend.

Which Identity Integration Model Should I Choose?​

PasskeyID supports two flexible integration paths. The right choice depends on where identity verification already occurs in your system.

Option 1: Configure an Identity Provider with LoginID​

Choose this option if:

  • You want LoginID to orchestrate your identity verification, or
  • You already use a supported third-party identity provider and want it embedded into your LoginID MFA flows.

In this model, you configure one or more identity providers at the application level. PasskeyID handles provider invocation and sends normalized identity results to your backend for approval via a secure webhook.

Proceed to the next section to configure your provider:

Identity Provider Setup

Option 2: Webhook-Based Identity (No Identity Provider)​

Choose this option if:

  • You already verify user identity within your own systems, or
  • You want LoginID to act as an identity witness and signing authority rather than performing verification itself.

In this model, no identity provider is configured in LoginID. During the MFA flow, LoginID generates a minimal identity event and sends it to your backend via a secure webhook.

Skip the provider setup and continue with:

Secure Webhook Setup

Identity Provider Setup​

Your identity provider must be configured in two steps:

  1. Create an identity provider at the organization level
  2. Assign the provider to an application

Organization Level Setup​

To enable identity in your MFA flows, you must first configure your identity provider at the organization level.

Navigate to the Organization Identity Provider Settings page in the Dashboard.

Create a Provider​

  1. Click Add New Identity Provider
  2. Select the identity provider you are currently using
  3. Fill out the required configuration fields for the selected provider
FieldDescription
NameA human-readable name for this SNA provider. Example: Prove SNA or Primary Prove Provider.
Description (Optional)A short description explaining how this provider is used. Example: Primary SNA provider for MFA flows.
API URLThe base URL LoginID will call when performing SNA lookups against Prove. This value is provided by Prove (for example, a sandbox or production endpoint).
API KeyThe API key issued by Prove used to authenticate requests from LoginID. Keep this value secure.
Default Failure PolicyDetermines behavior if the SNA request fails.
• SOFT – Allow fallback MFA methods
• HARD – Fail authentication
SNA Prove Auth Scopes (Optional)OAuth scopes required by Prove for SNA authentication (for example, read, write). Only required if specified by Prove.
SNA Prove Rate Limit (Optional)Maximum number of SNA requests per second sent to Prove. Leave blank to use default limits or enter a value provided by Prove.
SNA Prove Client ID (Optional)Client ID used if your Prove integration requires OAuth-style client credentials.

Activate the Provider​

  1. Click Submit to save the provider configuration
  2. Enable the provider by clicking the ellipsis (⋯) next to it and selecting Activate

Once activated, the identity provider becomes available to applications within your organization.

Assign an Identity Provider to an Application​

After creating and activating an identity provider, you must assign it to an application.

  1. Go to your Applications list
  2. Select the application you want to enable identity for
  3. Navigate to Settings → Identity
  4. Select your configured identity provider from the dropdown

Once assigned, the identity provider is enabled for the application’s MFA flows.

Application-Level Overrides​

After assigning a provider, you may adjust application-specific configuration options. These overrides apply only to the selected application and do not affect the organization-level configuration.

FieldDescription
Disable IdentityDisables the identity provider entirely for this application. When enabled, the provider will not be evaluated during MFA flows for this application, even if it is active at the organization level.
Disable Identity Provider on RegistrationWhen enabled, the identity provider will not be used during passkey creation flows for this application. This allows registration to proceed without identity checks while still using identity during other flows.
Disable Identity Provider on AuthenticationWhen enabled, identity checks will be skipped during user authentication. Other flows (e.g., MFA, registration) may still use identity unless separately disabled.
Include IP AddressDetermines whether the user’s IP address is included in identity requests. This may improve accuracy for identity providers that leverage IP-based or network-based verification signals.
Identity Failure PolicySets the behavior when identity evaluation fails.
• SOFT – Allow fallback MFA methods
• HARD – Fail authentication for this application.

Secure Webhook Setup​

PasskeyID uses a secure, server-to-server webhook to finalize identity verification during MFA flows.

The webhook is invoked synchronously and its response is authoritative. Approval allows the flow to continue, while rejection or error aborts passkey creation or authentication.

You may configure a webhook with or without an identity provider.

Webhook configuration is done at the application level.

Configure a Webhook for Your Application​

  1. Navigate to your Applications
  2. Select the application you want to configure
  3. Open the Webhooks tab in the left navigation menu

You will see the webhook configuration panel where you can define authentication and your webhook endpoint URL.

Webhook Configuration Options​

FieldDescription
Webhook Authentication MethodDefines how LoginID signs or authenticates webhook requests sent to your backend.
• JWT (Recommended) – Webhooks are signed with a JWT that you verify using your application’s public key. Ensures request authenticity and tamper resistance.
• None – No authentication. Recommended only for testing or isolated environments.
Webhook URIThe endpoint on your server that will receive webhook requests. This may be an HTTP(S) or gRPC URI. The endpoint must accept synchronous requests and return a valid response indicating approval or rejection. The implementation must match your selected authentication method.

Validation Test​

After configuring your webhook, you can verify that it is reachable and correctly by clicking the Check Status button.

This tool performs a synchronous test call to your webhook endpoint. It validates both connectivity and response handling based on your selected authentication method.

Validation EventDescription
Webhook Endpoint ReachabilityConfirms that the webhook URI is reachable over HTTPS and accepts POST requests.
JWT Signature Verification(JWT authentication only) - Verifies that the webhook request is signed correctly and can be validated using your application’s public key.
Payload Signature Certificate ValidationEnsures the signing certificate used for the webhook payload is valid and trusted.
Response ValidConfirms that your webhook returns a properly formatted JSON response with a valid approval or rejection decision.

Webhook Implementation Requirements​

To successfully approve identity verification requests, your webhook service must implement the following processing steps.

Webhook Processing Flow​

When LoginID calls your webhook endpoint:

  1. Your service receives a signed JWS request.
  2. The request signature must be verified.
  3. The payload must be parsed and evaluated according to your business logic.
  4. Your service returns a signed approval or rejection response.
  5. LoginID validates the response and continues or stops the authentication flow.

The webhook response is authoritative.

1. Verify Incoming Request Signature (Required)​

All webhook requests contain a JWS token signed by LoginID.

Your service must:

  • Parse the JWS header and payload.
  • Extract the following header fields:
    • alg — signing algorithm
    • jku — JWKS endpoint URL
    • kid — key identifier
{
"alg": "ES256",
"jku": "https://J6U676LM8G7OL8KHBJO53C62.api.loginid/fido2/v2/.well-known/jwks.json",
"kid": "app_J6U676LM8G7OL8KHBJO53C62_jwt",
"typ": "JWT"
}

Then:

  1. Fetch the JWKS from the provided jku URL.
  2. Locate the public key matching kid.
  3. Verify the JWS signature using the key and algorithm.
err := ctx.VerifyJWSSignature(ctx, jwsToken)
if err != nil {
return reject("invalid signature")
}

Reject the request if:

  • The signature is invalid
  • Required headers are missing
  • The JWKS cannot be fetched or verified

2. Decode and Inspect Identity Payload​

After verifying the signature:

  1. Decode the JWS payload.
  2. Extract the inner request payload.
  3. Base64-decode the embedded identity request.
{
"aud": "J6U676LM8G7OL8KHBJO53C62",
"exp": 1770227515,
"iat": 1770223915,
"req": "eyJ0cmFjZUlkIjoiRjc3QTFMSUw5U0tCQThJQVNDRTM2STlLIiwidGltZXN0YW1wIjoiMjAyNi0wMi0wNFQxMTo1MTo1NS4yMzkzOTYtMDU6MDAiLCJyZXF1ZXN0SGFzaCI6ImhHTVowbzREdjkwZmExbTFQSW1UdzIrOUxsNTlwZ2JCc3RJMlpsdlg5TEk9Iiwic2lnbmVkSGFzaCI6bnVsbCwiaWRlbnRpdHlEYXRhIjp7InByb3ZpZGVycyI6W119fQ==",
"sub": "webhook-request"
}

The identity payload typically includes:

  • traceId
  • requestHash
  • Provider responses (if identity providers are enabled)

Use this data to evaluate whether the identity verification should be approved.

{
"traceId": "F77A1LIL9SKBA8IASCE36I9K",
"timestamp": "2026-02-04T11:51:55.239396-05:00",
"requestHash": "hGMZ0o4Dv90fa1m1PImTw2+9Ll59pgbBstI2ZlvX9LI=",
"signedHash": null,
"identityData": {
"providers": []
}
}

3. Apply Business Logic​

Your service must decide whether to approve or reject the request.

Common decision logic may include:

  • Validating identity provider outcomes
  • Matching against internal records
  • Applying risk or fraud rules
  • Checking regulatory or compliance requirements

If the request is rejected, return a signed rejection response.

4. Generate Signed Response (Required)​

Your webhook must return a signed JWS response.

The response must:

  • Be signed using an X.509 certificate.
  • Include a header containing:
    • alg — signing algorithm
    • x5t — certificate thumbprint

The response payload should include:

  • appId
  • traceId
  • hashAlg
  • hashSalt
  • usernameHash
  • identityHash

The hashes allow LoginID to confirm integrity without exposing sensitive data.

func createResponse(
privateKey any,
certRaw []byte,
identity *IdentityPayload,
) (string, error) {
salt, _ := generateSalt()

hashSalt := base64.RawURLEncoding.EncodeToString(salt)

usernameHash := hashWithSalt(salt, []byte(identity.Username))

identityData := []byte(identity.AppID + identity.Username)
identityHash := hashWithSalt(salt, identityData)

response := ResponsePayload{
AppID: identity.AppID,
TraceID: identity.TraceID,
HashAlg: "sha256",
HashSalt: hashSalt,
UsernameHash: usernameHash,
IdentityHash: identityHash,
}

payloadJSON, _ := json.Marshal(response)

x5t := calculateCertThumbprint(certRaw)

headers := jws.NewHeaders()
headers.Set(jws.AlgorithmKey, jwa.ES256())
headers.Set("x5t", x5t)

signed, err := jws.Sign(
payloadJSON,
jws.WithKey(jwa.ES256(), privateKey, jws.WithProtectedHeaders(headers)),
)

return string(signed), err
}

func generateSalt() ([]byte, error) {
salt := make([]byte, 16)
_, err := rand.Read(salt)
return salt, err
}

func hashWithSalt(salt, data []byte) string {
combined := append(salt, data...)
hash := sha256.Sum256(combined)

return base64.RawURLEncoding.EncodeToString(hash[:])
}

func calculateCertThumbprint(certRaw []byte) string {
hash := sha256.Sum256(certRaw)
return base64.RawURLEncoding.EncodeToString(hash[:])
}

5. Return Response to LoginID​

Your endpoint must respond synchronously with:

{
"token": "<signed-jws-response>",
"crt": "<base64-encoded-x509-certificate>"
}

Setup SDK​

npm i @loginid/websdk3

Import and initialize an instance:

import { LoginIDMfa } from "@loginid/websdk3";

const lid = new LoginIDMfa({
baseUrl: process.env.LOGINID_BASE_URL,
});

Identity Verification with LoginID MFA SDK​

SDK-Level Identity Step

This section explains how PasskeyID integrates into a LoginID MFA session at the SDK level, focusing on the identity verification step and how it differs depending on whether/which an identity provider is configured.

PasskeyID always operates within an MFA session and is coordinated using a traceId, which acts as a client-defined external identifier for the entire transaction.

When Prove is configured as an identity provider, PasskeyID performs implicit identity verification using Silent Network Authentication (SNA). No user interaction is required.

The only requirement is to provide a phone number when starting the MFA session. An optional full name can be included to improve match accuracy.

await mfa.beginFlow(username, {
traceId,
phone,
name, // Optional — can improve accuracy
});

What happens next:

  1. The MFA session progresses normally.
  2. When the identity step is reached, PasskeyID automatically invokes Prove using SNA.
  3. The identity result is normalized and sent to your backend via a secure webhook.
  4. Your backend verifies the result and responds with approval or rejection.
  5. Based on your webhook response:
  • If approved, PasskeyID:
    • Creates an immutable audit record.
    • Continues the MFA session and initiates passkey creation.
  • If rejected, the identity step fails and the MFA session is terminated.

Once completed, the newly created passkey is considered identity-bounded.

info

traceId is a client-defined identifier that is propagated through every stage of the MFA session and included in all identity-related webhooks. It can be any arbitrary string (for example, a UUID).

Next Steps​

This section focused specifically on the identity step within an MFA session.

For a complete, end-to-end example showing:

  • MFA session initiation
  • Passkey creation and authentication
  • Next-step decisions

See the MFA Full Example documentation.