# Get a list of audit logs Source: https://docs.hanko.io/api-reference/admin/audit-logs/get-a-list-of-audit-logs openapi-admin get /audit_logs # Create an email for a user Source: https://docs.hanko.io/api-reference/admin/email-management/create-an-email-for-a-user openapi-admin post /users/{id}/emails # Get an email of a user Source: https://docs.hanko.io/api-reference/admin/email-management/get-a-email-by-id openapi-admin get /users/{id}/emails/{email_id} # Get a list of emails for a user Source: https://docs.hanko.io/api-reference/admin/email-management/get-a-list-of-emails openapi-admin get /users/{id}/emails # Remove an email from a user Source: https://docs.hanko.io/api-reference/admin/email-management/remove-a-email-by-id openapi-admin delete /users/{id}/emails/{email_id} # Set email as primary Source: https://docs.hanko.io/api-reference/admin/email-management/set-an-email-as-primary openapi-admin post /users/{id}/emails/{email_id}/set_primary # Get Prometheus metrics. Source: https://docs.hanko.io/api-reference/admin/metrics/get-prometheus-metrics openapi-admin get /metrics # Delete the OTP secret from a user Source: https://docs.hanko.io/api-reference/admin/otp-management/delete-otp openapi-admin delete /users/{id}/otp # Get the OTP secret metadata of a user Source: https://docs.hanko.io/api-reference/admin/otp-management/get-otp openapi-admin get /users/{id}/otp # Create a password for a user Source: https://docs.hanko.io/api-reference/admin/password-management/create-password openapi-admin post /users/{id}/password # Delete the password of a user Source: https://docs.hanko.io/api-reference/admin/password-management/delete-password openapi-admin delete /users/{id}/password # Get password metadata of a user Source: https://docs.hanko.io/api-reference/admin/password-management/get-password openapi-admin get /users/{id}/password # Update the password for a user Source: https://docs.hanko.io/api-reference/admin/password-management/update-password openapi-admin put /users/{id}/password # Create a new session token for a user Source: https://docs.hanko.io/api-reference/admin/session-management/create-session openapi-admin post /sessions # Delete a session from a user Source: https://docs.hanko.io/api-reference/admin/session-management/delete-session openapi-admin delete /users/{id}/sessions/{session_id} # Get users active sessions Source: https://docs.hanko.io/api-reference/admin/session-management/list-sessions openapi-admin get /users/{id}/sessions # Status page Source: https://docs.hanko.io/api-reference/admin/status/status-page openapi-admin get / Return information about the API status. Returns a 500 if there are issues with database connectivity. # Create a new user Source: https://docs.hanko.io/api-reference/admin/user-management/create-a-new-user openapi-admin post /users # Delete a user by ID Source: https://docs.hanko.io/api-reference/admin/user-management/delete-a-user-by-id openapi-admin delete /users/{id} # Get a list of users Source: https://docs.hanko.io/api-reference/admin/user-management/get-a-list-of-users openapi-admin get /users # Get a user by ID Source: https://docs.hanko.io/api-reference/admin/user-management/get-a-user-by-id openapi-admin get /users/{id} # Update a user by ID Source: https://docs.hanko.io/api-reference/admin/user-management/update-a-user-by-id openapi-admin patch /users/{id} Updates a subset of user-level attributes. Other sub-resources (e.g. emails, credentials) are managed via dedicated endpoints and are not updated via this endpoint. # Get metadata of a user Source: https://docs.hanko.io/api-reference/admin/user-metadata-management/get-metadata-of-a-user get /users/{id}/metadata # Patch metadata of a user Source: https://docs.hanko.io/api-reference/admin/user-metadata-management/patch-metadata-of-a-user patch /users/{id}/metadata Patch metadata of a user Updates a users metadata by deep merging the metadata patch from the request with existing metadata. Set the entire request to `null` to clear all metadata: Set any of `public_metadata`, `private_metadata`, `unsafe_metadata` to `null` to clear metadata for that category. An empty object (`{}`) for the top level request object or an empty object for `public_metadata`, `private_metadata` or the `unsafe_metadata` property represent a noop patch. Unknown top level keys besides `public_metadata`, `private_metadata` or `unsafe_metadata` are ignored. All other top level request values (e.g. an empty string, a non-empty string, an array) result in a bad request. # Delete a WebAuthn credential from a user Source: https://docs.hanko.io/api-reference/admin/webauthn-credential-management/delete-webauthn-credential openapi-admin delete /users/{id}/webauthn_credentials/{credential_id} # Get a WebAuthn credential of a user Source: https://docs.hanko.io/api-reference/admin/webauthn-credential-management/get-webauthn-credential openapi-admin get /users/{id}/webauthn_credentials/{credential_id} # Get a list of all WebAuthn credentials for a user Source: https://docs.hanko.io/api-reference/admin/webauthn-credential-management/list-webauthn-credentials openapi-admin get /users/{id}/webauthn_credentials # Create a new database webhook Source: https://docs.hanko.io/api-reference/admin/webhooks/create-a-webhook openapi-admin post /webhooks # Delete a webhook by ID Source: https://docs.hanko.io/api-reference/admin/webhooks/delete-a-webhook openapi-admin delete /webhooks/{id} # Get a list of webhooks Source: https://docs.hanko.io/api-reference/admin/webhooks/get-a-list-of-webhooks openapi-admin get /webhooks Returns a list of all configured webhooks. # Get a webhook by ID Source: https://docs.hanko.io/api-reference/admin/webhooks/get-a-webhook-by-id openapi-admin get /webhooks/{id} # Update a webhook by ID Source: https://docs.hanko.io/api-reference/admin/webhooks/update-a-webhook openapi-admin put /webhooks/{id} # Login Source: https://docs.hanko.io/api-reference/flow/login post /login Initialize or advance a login flow. # Profile Source: https://docs.hanko.io/api-reference/flow/profile post /profile Initialize or advance a profile flow. # Registration Source: https://docs.hanko.io/api-reference/flow/registration post /registration Initialize or advance a registration flow. # Token exchange Source: https://docs.hanko.io/api-reference/flow/token-exchange post /token_exchange Initialize or advance a token exchange flow. This flow is only available if SAML is enabled. # Add a new email address to the current user. Source: https://docs.hanko.io/api-reference/public/email-management/add-a-new-email-address-to-the-current-user openapi-public post /emails Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Delete an email address Source: https://docs.hanko.io/api-reference/public/email-management/delete-an-email-address openapi-public delete /emails/{id} Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Get a list of emails of the current user. Source: https://docs.hanko.io/api-reference/public/email-management/get-a-list-of-emails-of-the-current-user openapi-public get /emails Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Marks the email address as primary email Source: https://docs.hanko.io/api-reference/public/email-management/marks-the-email-address-as-primary-email openapi-public post /emails/{id}/set_primary Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Finalize passcode login Source: https://docs.hanko.io/api-reference/public/passcode/finalize-passcode-login openapi-public post /passcode/login/finalize Finalize a passcode login. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). Finalize a passcode login given the `id` of the passcode and the actual `code` provided in the email sent to the user during initialization. On success, sets the User's `verified` status to `true` # Initialize passcode login Source: https://docs.hanko.io/api-reference/public/passcode/initialize-passcode-login openapi-public post /passcode/login/initialize Initialize a passcode login. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). Initialize a passcode login for the user identified by `user_id`. Sends an email containing the actual passcode to the user's primary email address or to the address specified through `email_id`. Returns a representation of the passcode. # Create/Set a password Source: https://docs.hanko.io/api-reference/public/password/createset-a-password openapi-public put /password Create a or update an existing password for a user. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). Create a or update an existing `password` for the user identified by `user_id`. This endpoint is only available if passwords have been enabled via [configuration](https://github.com/teamhanko/hanko/blob/main/backend/docs/Config.md#hanko-backend-config) option `passwords.enabled`. # Do password login Source: https://docs.hanko.io/api-reference/public/password/do-password-login openapi-public post /password/login Perform a password login. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). Perform a password login for the user identified by `user_id` and a given `password`. This endpoint is only available if passwords have been enabled via [configuration](https://github.com/teamhanko/hanko/blob/main/backend/docs/Config.md#hanko-backend-config) option `passwords.enabled`. # Get a SAML provider Source: https://docs.hanko.io/api-reference/public/saml/get-a-saml-provider get /saml/provider Get a SAML service provider config for a provided domain. # Get SAML Metadata Source: https://docs.hanko.io/api-reference/public/saml/get-saml-metadata get /saml/metadata Download SAML service provider metadata or public certificate. # SAML identity provider callback Source: https://docs.hanko.io/api-reference/public/saml/saml-identity-provider-callback post /saml/callback Callback endpoint called by the identity provider after successful login. # Validate a session Source: https://docs.hanko.io/api-reference/public/session-management/validate-a-session get /sessions/validate Validate a session using a cookie header or an authorization header. This is a passive check that does not update the session's internal last activity timestamp. # Validate a session Source: https://docs.hanko.io/api-reference/public/session-management/validate-a-session-1 post /sessions/validate Validate a session using a session token in a request body. This endpoint updates the session's internal last activity timestamp. This extends the idle timeout window if configured). # Status page Source: https://docs.hanko.io/api-reference/public/status/status-page openapi-public get / Return information about the API status. Returns a 500 if there are issues with database connectivity. # Initialize third party login Source: https://docs.hanko.io/api-reference/public/third-party/initialize-third-party-login openapi-public get /thirdparty/auth Initialize an OAuth-backed (authorization code grant type) login with a third party provider by redirecting to the specified provider login URL to retrieve an authorization code. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Third party provider callback Source: https://docs.hanko.io/api-reference/public/third-party/third-party-provider-callback openapi-public get /thirdparty/callback Callback endpoint called by the third party provider after successful login. # Exchange one time token for session Source: https://docs.hanko.io/api-reference/public/token/exchange-one-time-token-for-session openapi-public post /token Provide a one time token (e.g. obtained through the [thirdparty callback](#tag/Third-Party/operation/thirdPartyCallback)) to retrieve a session JWT as cookie and/or via `X-Auth-Token` header. # Create a user Source: https://docs.hanko.io/api-reference/public/user-management/create-a-user openapi-public post /users Used to create a new user. To disable this endpoint, `config.account.allow_signup` must be set to false. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Deletes the current user Source: https://docs.hanko.io/api-reference/public/user-management/deletes-the-current-user openapi-public delete /user Used to delete the current user. Note that `config.account.allow_deletion` must be set to true. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Get a user by ID Source: https://docs.hanko.io/api-reference/public/user-management/get-a-user-by-id openapi-public get /users/{id} # Get the current user Source: https://docs.hanko.io/api-reference/public/user-management/get-the-current-user-id openapi-public get /me Retrieve data for the current user (i.e. the subject of the JWT given in a cookie or as a bearer token). # Get user details by email Source: https://docs.hanko.io/api-reference/public/user-management/get-user-details-by-email openapi-public post /user Retrieve details for user corresponding to the given `email`. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Log out the current user Source: https://docs.hanko.io/api-reference/public/user-management/log-out-the-current-user openapi-public post /logout Logs out the user by removing the authorization cookie. # Deletes a WebAuthn credential Source: https://docs.hanko.io/api-reference/public/webauthn/deletes-a-webauthn-credential openapi-public delete /webauthn/credentials/{id} Deletes the specified WebAuthn credential. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Finalize WebAuthn login Source: https://docs.hanko.io/api-reference/public/webauthn/finalize-webauthn-login openapi-public post /webauthn/login/finalize Finalize a login with Webauthn. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). Finalize a login with Webauthn using the WebAuthn API response to a `navigator.credentials.get()` call. The Webauthn API uses binary data represented by ArrayBuffers for certain input/output values. The Hanko API returns these values as base64url-encoded, so they must be converted to ArrayBuffers when passed to the Webauthn API. Similarly, Webauthn API output must be converted to base64url-encoded values when passed to the Hanko API (e.g. using the [webauthn-json](https://github.com/github/webauthn-json) library). # Finalize WebAuthn registration Source: https://docs.hanko.io/api-reference/public/webauthn/finalize-webauthn-registration openapi-public post /webauthn/registration/finalize Finalize a registration with Webauthn. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). Finalize a registration with Webauthn using the WebAuthn API response to a `navigator.credentials.create()` call. The Webauthn API uses binary data represented by ArrayBuffers for certain input/output values. The Hanko API returns these values as base64url-encoded, so they must be converted to ArrayBuffers when passed to the Webauthn API. Similarly, Webauthn API output must be converted to base64url-encoded values when passed to the Hanko API (e.g. using the [webauthn-json](https://github.com/github/webauthn-json) library). # Get a list of WebAuthn credentials Source: https://docs.hanko.io/api-reference/public/webauthn/get-a-list-of-webauthn-credentials openapi-public get /webauthn/credentials Returns a list of WebAuthn credentials assigned to the current user. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Initialize WebAuthn login Source: https://docs.hanko.io/api-reference/public/webauthn/initialize-webauthn-login openapi-public post /webauthn/login/initialize Initialize a login with Webauthn. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). Returns a JSON representation of CredentialRequestOptions for use with the Webauthn API's `navigator.credentials.get()`. Omitting the optional request body or using an empty JSON object results in generation of request options for a login using a [discoverable credential](https://www.w3.org/TR/webauthn-2/#client-side-discoverable-public-key-credential-source) (i.e. they will not contain [allowCredentials](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialrequestoptions-allowcredentials)). The Webauthn API uses binary data represented by ArrayBuffers for certain input/output values. The Hanko API returns these values as base64url-encoded, so they must be converted to ArrayBuffers when passed to the Webauthn API. Similarly, Webauthn API output must be converted to base64url-encoded values when passed to the Hanko API (e.g. using the [webauthn-json](https://github.com/github/webauthn-json) library). # Initialize WebAuthn registration Source: https://docs.hanko.io/api-reference/public/webauthn/initialize-webauthn-registration openapi-public post /webauthn/registration/initialize Initialize a registration with Webauthn. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). Returns a JSON representation of CredentialCreationOptions for use with the Webauthn API's `navigator.credentials.create()`. The Webauthn API uses binary data represented by ArrayBuffers for certain input/output values. The Hanko API returns these values as base64url-encoded, so they must be converted to ArrayBuffers when passed to the Webauthn API. Similarly, Webauthn API output must be converted to base64url-encoded values when passed to the Hanko API (e.g. using the [webauthn-json](https://github.com/github/webauthn-json) library). # Updates a WebAuthn credential Source: https://docs.hanko.io/api-reference/public/webauthn/updates-a-webauthn-credential openapi-public patch /webauthn/credentials/{id} Updates the specified WebAuthn credential. Only credentials assigned to the current user can be updated. Deprecated. Please use the [Flow API](/api-reference/flow/registration) instead. [What's the Flow API?](/using-the-api/understanding-the-flow-api). # Get JSON Web Key Set Source: https://docs.hanko.io/api-reference/public/well-known/get-json-web-key-set openapi-public get /.well-known/jwks.json Retrieve a [JSON Web Key Set](https://www.rfc-editor.org/rfc/rfc7517#section-5) (JWKS) object containing the public `keys` used to verify JSON Web Tokens (JWT) issued by the Hanko API and signed using the RS256 signing algorithm. # Get public Hanko configuration Source: https://docs.hanko.io/api-reference/public/well-known/get-public-hanko-configuration openapi-public get /.well-known/config Retrieve public backend configuration options. Useful, for example, for conditionally constructing a UI based on the options (e.g. don't show password inputs when they are disabled). # FAQ Source: https://docs.hanko.io/community-support/faq A collection of common questions that we hear from Hanko users. Yes, Hanko is open source and all source code is published in the Hanko monorepo on GitHub. Hanko backend is licensed under AGPLv3 and the Hanko Frontend SDK as well as Hanko Elements are MIT licensed. Please note that the Hanko Cloud infrastructure and the Hanko Cloud Console are closed source. Hanko Cloud provides a hosted Hanko backend, simplifying the initiation and management of new Hanko projects. It comes with out-of-the-box user management and analytics. Yes, you can self-host. Please refer to this [guide](https://github.com/teamhanko/hanko/tree/main/backend#hanko-backend). You can access most of your data via the Admin API. This data does not include password hashes or TOTP secrets. If you need these as well, please contact us and we will provide a complete dataset for migrating to self-hosted Hanko or another authentication provider. Check out our [quickstart guides](/quickstarts/overview) to help you integrate Hanko with your favorite frameworks. Yes, absolutely. However, we currently do not have any mobile SDKs available, these are on our roadmap for future development. In the meantime, you can make your mobile client work directly with the Hanko API. We recommend getting started with [this guide](/using-the-api/understanding-the-flow-api). Yes, we provide a dedicated product for that: The Hanko Passkey API. Refer to our [Passkey API docs](/passkey-api/introduction) for more information. Join our [Discord Community](https://www.hanko.io/community) and feel free to ask any questions you might have there. # Get help Source: https://docs.hanko.io/community-support/get-help Reach out to us with your questions, we're happy to help. } > Join us on Discord to hang out with other users and meet our team. } > Schedule a chat with our team. # Troubleshoot Source: https://docs.hanko.io/community-support/troubleshoot A guide to help you with common issues faced when working with Hanko. Console Hanko Auth Component CORS errors usually happen when your app URL isn’t correctly set up in Hanko Cloud. If you’re developing locally, make sure to add something like `http://localhost:3000`. For production, use your live URL. Follow this [guide](/setup-hanko-cloud) for a smooth Hanko Cloud setup. Also, double-check that your app’s API URL is correct — even a missing or extra character when copying it from the Hanko Console can trigger a CORS error. Console Hanko Auth Component This error typically arises when the `API URL` has been incorrectly configured. Depending on your framework, you may need to prefix your URLs with PUBLIC, NEXT\_PUBLIC, or another specific prefix. This prefixing ensures that these environment variables are exposed to the browser and can be accessed by your frontend. Here are some of the examples ```sh .env theme={null} Next.js NEXT_PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io Nuxt NUXT_PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io SvelteKit PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io React REACT_APP_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` You might get `"r" is read-only` error after you deploy a CRA (Create React App). To fix it you'll need to add `@babel/core` as a dependency in your project. You can do this by running the following command: ```sh theme={null} npm install @babel/core ``` Feel free to open a [GitHub Issue](https://github.com/teamhanko/hanko/issues) or join our [Discord Community](https://www.hanko.io/community). We're here to help! # Custom domain Source: https://docs.hanko.io/guides/custom-domain/custom-domain Configure a custom domain for your Hanko Cloud project to improve compatibility and your users' experience.
**Hanko Custom Domain Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to configure a custom domain for your Hanko project. You'll learn to set up DNS records, configure SSL certificates, and update your applications to use your branded authentication domain. **Key Technologies**: * DNS Management (CNAME Records) * SSL/TLS Certificates * Domain Configuration * Hanko Cloud Console **Prerequisites**: * Active Hanko Cloud project * Domain name that you control * Access to your domain's DNS settings * Basic understanding of DNS configuration **Tasks You'll Complete**: * Set up CNAME record in your DNS configuration * Configure custom domain in Hanko Console * Verify SSL certificate provisioning * Update OAuth provider redirect URLs * Modify application API endpoints * Test authentication flows with custom domain
### Setting up a custom domain for your Hanko project This guide explains the benefits of using a custom domain with Hanko and walks you through the configuration process. *** #### Why use a custom domain? Using a custom domain for your Hanko authentication project provides several important advantages: * **Better compatibility with 3rd-Party OAuth providers** With OAuth providers, the redirect URL or redirect domain is displayed on the user’s consent screen. Using a custom domain means that your own domain/URL (e.g., `auth.yourapp.com`) will be shown instead of the default Hanko domain (`hanko.io`). * **3rd-Party cookie tracking prevention** Some modern browsers block 3rd-party cookies by default. A custom domain allows cookies to belong to your domain and work reliably in these browsers. * **Google verified app features:** If using Google OAuth, having a custom domain allows your application to display your app’s logo and leverage other branding features (e.g., custom scopes). (See [Google Documentation](https://support.google.com/cloud/answer/13463073?hl=en) for more info) #### How to set up a custom domain To set up your custom domain for authentication, follow these steps: 1. **Create a CNAME record in your DNS configuration:** Configure a CNAME record in your domain's DNS settings to point to `cname.hanko.io` The process for this varies by DNS provider, but most providers will have instructions to follow. Here are links to updating the appropriate DNS records for some popular providers: * [Amazon Web Services (Route 53\)](https://aws.amazon.com/premiumsupport/knowledge-center/create-subdomain-route-53/) * [Google Cloud Platform (Cloud DNS)](https://cloud.google.com/dns/docs/set-up-dns-records-domain-name#create_a_cname_record_for_the_www_subdomain) * [Cloudflare](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/) * [GoDaddy](https://www.godaddy.com/help/add-a-cname-record-19236) 2. **Configure the custom domain in the Hanko Console:** * Log in to the [Hanko Console](https://cloud.hanko.io). * Navigate to **Project settings > Custom domain**. * Enter your custom domain (e.g., `auth.yourapp.com`) in the input field and save. After setting up the custom domain, please allow a few minutes for the changes to propagate through the DNS system before they take effect. When the custom domain is set up, your project will no longer be reachable through the previous API URL. #### Updating Your application for the custom domain After setting up the custom domain, you'll need to update your application's configuration to use the new URLs across various places: 1. **Change your API URL:** After setting up the custom domain, update the API URL in your Hanko Elements configuration or frontend-sdk initialization, and in your backend code. 2. **Update redirect URLs:** * If you're using 3rd-party connections (e.g., Google, SAML), ensure that all redirect URL configurations are updated. * Retrieve the new redirect URL from the **Project Settings > Social connections** and **Project settings > Enterprise connections** * Update these URLs in your 3rd-party provider configurations (e.g., Google, Azure AD). # Send Hanko emails using your own SMTP server Source: https://docs.hanko.io/guides/email-delivery/custom-smtp-server Learn how to set up a custom SMTP server to send Hanko emails through your own SMTP server.
**Hanko Custom SMTP Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to configure your own SMTP server to send authentication emails through Hanko. You'll learn to replace Hanko's default email delivery with your custom SMTP provider for better brand consistency and email deliverability control. **Key Technologies**: * SMTP Protocol * Email Service Providers (Resend, SendGrid, etc.) * Hanko Cloud Console * DNS Configuration * Email Authentication (SPF, DKIM) **Prerequisites**: * Hanko Pro or Enterprise plan subscription * SMTP server credentials from your email provider * Basic understanding of email server configuration * Access to Hanko Cloud Console **Tasks You'll Complete**: * Gather SMTP server credentials from your provider * Configure custom SMTP settings in Hanko Cloud * Test email delivery functionality * Verify email authentication and deliverability * Monitor email sending performance
This feature is only available in the Pro or Enterprise [plans](https://www.hanko.io/pricing). 1. **Gather SMTP server credentials** from your email provider. You'll need the following information: * Host (SMTP server address) * Port (typically 587 for TLS or 465 for SSL) * Username (often your email address) * Password (or API key for some providers) * Sender email address (must be verified with your provider) If you're using [Resend](https://resend.com), follow our detailed [tutorial](https://www.hanko.io/blog/send-hanko-auth-emails-from-your-domain-via-resend) for setup instructions. 2. **Access your project settings** by logging into [Hanko Cloud](https://cloud.hanko.io) and selecting your project. 3. **Navigate to email configuration** at `Settings > Email delivery`. 4. **Configure your SMTP server** by enabling the `Custom SMTP` Server option, entering your credentials, and clicking `Save`. Custom SMTP Server # How to customize Hanko's emails Source: https://docs.hanko.io/guides/email-delivery/email-delivery Send Hanko emails with your own text and style.
**Hanko Custom Emails Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to implement custom email delivery for Hanko authentication flows. You'll learn to disable Hanko's default email service and handle authentication emails through your own email infrastructure and templates. **Key Technologies**: * Webhooks (email.send events) * Email Service Providers * HTML Email Templates * JWT Token Processing * Hanko Cloud Console **Prerequisites**: * Hanko Pro or Enterprise plan subscription * Email service provider account * Webhook endpoint development capability * Basic understanding of email delivery systems * JWT token processing knowledge **Tasks You'll Complete**: * Create webhook for email.send events * Disable Hanko's default email delivery * Process webhook payloads for email data * Design custom email templates * Implement email sending logic * Test custom email delivery flows
This guide walks you through implementing custom email delivery instead of using Hanko's default email service. ## Create a webhook Set up a webhook subscription for the `email.send` event. This webhook triggers whenever Hanko needs to send an authentication email. New to webhooks? Check out our comprehensive [Webhooks guide](/guides/webhooks) first. ## Disable email delivery by Hanko This feature is only available in the Pro or Enterprise [plans](https://www.hanko.io/pricing). Log in to Hanko Cloud, select your organization and project, then navigate to `Settings > Email delivery`. Set the `Email delivery` setting to `Off` to disable default email sending. Once disabled, Hanko will no longer send emails for you. All email sending becomes your responsibility through webhook handling. ## Send custom emails When Hanko needs to send an email, the `email.send` webhook event triggers with all necessary data for custom email delivery. The webhook token payload contains comprehensive email information: ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "subject": "Use passcode 325139 to verify your email address", "body_plain": "Enter the following passcode to verify your email address:\n\n325139\n\nThe passcode is valid for 5 minutes.", "to_email_address": "test@example.com", "delivered_by_hanko": false, "language": "en", "type": "passcode", "data": { "service_name": "Test Service ABC", "otp_code": "325139", "ttl": 300, "valid_until": 1737128997 } }, "evt": "email.send", "exp": 1737128997, "iat": 1737128697, "sub": "hanko webhooks" } ``` The recipients the token is intended for The subject line of the email The plain text version of the email body The HTML version of the email body (nullable) The recipient’s email address Indicates whether the email was delivered by Hanko (`true`) or not (`false`). Deprecated, rely on `language` instead. The preferred language for the email content. The preferred language for the email content. The type of the email being sent or to be sent. Available options: `login`, `email_login_attempted`, `email_registration_attempted`, `email_verification`, `recovery`, `security_notification` Additional data. The name of the service set in the Console as the project name The passcode the user can use to log in The validity duration of the passcode in seconds The Unix timestamp indicating when the passcode expires The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued The `data` property contains type-specific information for email personalization. This structure varies based on the email type being sent (verification, password reset, etc.). Use the webhook data to compose and deliver emails through your preferred email service provider or custom infrastructure, giving you complete control over email design and delivery. # Set up SAML SSO with Auth0 Source: https://docs.hanko.io/guides/enterprise-sso/auth0 Learn how to set up enterprise connections in Hanko for customers using Auth0 as SAML identity provider.
**Hanko Auth0 SAML Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to configure Auth0 as a SAML identity provider for your Hanko project, enabling secure single sign-on authentication for enterprise users. **Key Technologies**: * SAML 2.0 * XML digital signatures * Auth0 identity provider * SAML assertions **Prerequisites**: * Active Auth0 account * Hanko Cloud project * Basic understanding of SAML authentication protocols * Admin access to both Auth0 and Hanko Cloud dashboards **Tasks You'll Complete**: * Set up SAML application in Auth0 dashboard * Configure SAML addon with proper ACS URL and settings * Set up attribute mapping for email claims * Create enterprise connection in Hanko Cloud * Test integration using IdP-initiated flow * Verify authentication workflow functions properly
## Prerequisites You need your project's SAML Assertion Consumer Service (ACS) URL. ### Service Provider ACS URL To find the Assertion Consumer Service (ACS) URL for your project: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Enterprise connections`. 3. Under `Enterprise connections` find the `Redirect URL` panel. 4. Copy and save the URL. How to find the Assertion Consumer Service URL in the Hank Cloud enterprise settings of a project ## Create an Auth0 application 1. Sign up for an [Auth0 account](https://auth0.com/signup) or [sign in](https://manage.auth0.com/) to access your dashboard. 2. On your dashboard, select `Applications > Applications` in the left sidebar. 3. Click `Create application` to create an application. Create an Auth0 application from the admin dashboard 4. In the shown modal, enter a name for your application. 5. Select `Regular Web Applications` as the application type. 6. Click `Create` to create the application. You should be redirected to the application's dashboard. Create an Auth0 application from the admin dashboard 7. On the application's dashboard, select `Addons` in the top tab navigation. 8. Click on the `SAML2 Web App` panel. Create an Auth0 application from the admin dashboard 9. In the shown modal, select `Settings` in the top tab navigation. 10. In the `Application Callback URL` input provide the ACS URL you obtained as described in [Prerequisites - Service Provider ACS URL](#service-provider-acs-url). Provide Hanko tenant ACS URL in SAML addon settings 11. Scroll down and select `Enable` to enable the configured SAML addon. Enable configured SAML addon 12. Select the `Usage` tab in the top tab navigation. 13. Find `Identity Provider Metadata` and copy the address of `Download` link. You need this for configuring the enterprise connection with Hanko in the next section. Copy identity provider metadata URL ### Attribute mapping SAML SSO integration with Hanko requires an email address attribute in the IdP's SAML response. The attribute must be available under the name `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`. Auth0 uses this name by default for the `emailaddress` attribute, so no additional configuration is required. ## Configure an enterprise connection 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Enterprise connections`. 3. Under `Connections`, click `New connection`. Create a new enterprise connection 4. In the shown modal provide the following data: * A `Name` for the connection. * A `Domain` for the connection. When users authenticate via SAML SSO, the domain of the email address provided as an identifier at the start of an authentication flow must match the domain configured here. * A `Metadata URL`. This is the URL you copied in step 13 in [Create an Auth0 application](#create-an-auth0-application). * Select whether you want skip email verification for this provider. 5. Click `Save` to create the connection. Provide enterprise connection data ## Testing your integration To test your integration via [IdP-initiated](/guides/enterprise-sso/introduction#identity-provider-initiated-sso) flow: 1. Navigate to the SAML Addon configuration for your application (see step 8 in [Create an Auth0 application](#create-an-auth0-application)). 2. In the `Usage` tab, find the `Identity Provider Login URL` and click the link. Use the SAML Addons Identity Provider Login URL to test your integration via IdP-initiated login # Set up SAML SSO with Microsoft Entra Source: https://docs.hanko.io/guides/enterprise-sso/entra Learn how to set up enterprise connections in Hanko for customers using Microsoft Entra as SAML identity provider.
**Hanko Microsoft Entra SAML Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to configure Microsoft Entra ID (formerly Azure AD) as a SAML identity provider for your Hanko project, enabling seamless single sign-on authentication for enterprise users. **Key Technologies**: * SAML 2.0 * XML digital signatures * Microsoft Entra ID * Azure Active Directory * SAML assertions **Prerequisites**: * Active Microsoft Entra account * Hanko Cloud project * Basic understanding of SAML authentication protocols * Admin access to both Microsoft Entra and Hanko Cloud dashboards **Tasks You'll Complete**: * Create custom enterprise application in Microsoft Entra * Configure SAML single sign-on settings * Set up entity ID and ACS URL configuration * Configure attribute mapping for email claims * Assign users to the application * Create enterprise connection in Hanko Cloud * Test integration using IdP-initiated flow
## Prerequisites You need your project's SAML Assertion Consumer Service (ACS) URL and the Service Provider (SP) Entity ID. ### Service Provider Entity ID The SP Entity ID for your Hanko project is equal to the API URL of your project. To find the API URL for your project: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Dashboard`. 3. Copy and save the `API URL`. Obtain the API URL from the Hanko Cloud project dashboard ### Service Provider ACS URL To find the Assertion Consumer Service (ACS) URL for your project: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Enterprise connections`. 3. Under `Enterprise connections` find the `Redirect URL` panel. 4. Copy and save the URL. Obtain the Assertion Consumer Service URL in the Hanko Cloud enterprise settings of a project ## Create a Microsoft Entra application 1. Sign up or sign in with [Microsoft Entra](https://entra.microsoft.com/). 2. Once you're logged in, select `Identity > Applications > Enterprise Applications` in the left sidebar. 3. Click `New Application`. This will open the `Microsoft Entra Gallery`. Create a new Entra application 4. In the `Microsoft Entra Gallery`, click `Create your own appplication`. 5. Give your application a name. 6. Select `Integrate any other application you don't find in the gallery (Non-gallery)`. 7. Click `Create` to create the application. Create a new custom Entra application 8. Once your app is created, select `Single sign-on` in the application sidebar. 9. Select `SAML` as the SSO method. Configure new custom Entra application to use SAML as SSO method 10. Find the `Basic SAML configuration` panel and click `Edit`. Configure new custom Entra application to use SAML as SSO method 11. Under `Identifier (Entity ID)` click `Add identifier` and enter you project API URL (see [Prerequisites - Service Provider Entity ID](#service-provider-entity-id)). 12. Under `Reply URL (Assertion Consumer Service URL)` click `Add reply URL` and enter your ACS URL (see [Prerequisites - Service Provider ACS URL](#service-provider-acs-url)). 13. Click `Save`. Configure Entity ID and ACS URL in the basic SAML settings 14. In the `SAML Certificates` panel, find the `App Fedration Metadata Url` and copy it. You need this for configuring the enterprise connection with Hanko. Obtain IdP Metadata URL from SAML certificates settings ### Attribute mapping SAML SSO integration with Hanko requires an email address attribute in the IdP's SAML response. To ensure this attribute is present: 1. In your application's `Single sign-on` configuration, find the `Attributes & Claims` panel and click `Edit`. Access SAMl attribute mappings through Attributes & Claims panel 2. There should be `Additional Claims` listed that have been added to your application per default. Find the claim that maps the Entra user's `user.email` property and click it. Select email address attribute mapping 3. Ensure that the `Name` is equal to `emailaddress` and the `Namespace` is equal to `http://schemas.xmlsoap.org/ws/2005/05/identity/claims`. 4. If your users do not have an email set for the `user.email` property, choose a different source for the mapping. Note that the email address value present in this attribute is used to [provision and link accounts](/guides/enterprise-sso/introduction#account-provisioning-and-linking). This means that any new accounts created at your Hanko project will use this email address value and any existing accounts in your Hanko project will be linked via this email address value. Ensure email address attribute name and namepsace matches defaults ### Assign users to your application To enable users to log in, you need to assign users to the application. 1. Select `Identity > Applications > Enterprise Applications` in the left sidebar. 2. Select your application, then select `Manage > Properties`. 3. Ensure that your application is enabled for users to sign-in. 4. Choose whether user assignment is required for this app. If set to `No`, all users will be able to sign in. 5. Choose whether this app is visible to users. If this option is set to yes, then assigned users will see the application on `My Apps` in their profile and the O365 app launcher. Configure custom application properties to make the app available to users 6. If you selected `Yes` in step 4, then select `Manage > Users and groups`. 7. Click `Add user/group`. Configure users and groups for custom application 8. Under `Users`, click `None selected`/`X user selected`. 9. Select the users you want to assign. 10. Click `Select`. Select and assign specific users to the application ## Configure an enterprise connection 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Enterprise connections`. 3. Under `Connections`, click `New connection`. Create a new enterprise connection in the Hanko Cloud project settings 4. In the shown modal provide the following data: * A `Name` for the connection. * A `Domain` for the connection. When users authenticate via SAML SSO, the domain of the email address provided as an identifier at the start of an authentication flow must match the domain configured here. * A `Metadata URL`. This is the URL you copied in step 14 in [Create a Microsoft Entra application](#create-a-microsoft-entra-application). * Select whether you want skip email verification for this provider. 5. Click `Save` to create the connection. Provide name, domain, metadata URL and email verification requirement for a new enterprise connection ## Testing your integration To test your integration via [IdP-initiated](/guides/enterprise-sso/introduction#identity-provider-initiated-sso) flow: 1. Navigate to the `Single sign-on` configuration for your application (see step 8 in [Create a Microsoft Entra application](#create-a-microsoft-entra-application)). 2. Find the `Test single sign-on with My App` panel and click the `Test`. Testing IdP-initiated single sign-on with your Entra application # Set up SAML SSO with Google Workspace Source: https://docs.hanko.io/guides/enterprise-sso/google Learn how to set up enterprise connections in Hanko for customers using Google Workspace as SAML identity provider.
**Hanko Google Workspace SAML Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to configure Google Workspace as a SAML identity provider for your Hanko project, enabling secure single sign-on authentication for Google Workspace users. **Key Technologies**: * SAML 2.0 * XML digital signatures * Google Workspace * Google Admin Console * SAML assertions **Prerequisites**: * Active Google Workspace account with admin privileges * Hanko Cloud project * Basic understanding of SAML authentication protocols * Ability to host XML metadata files publicly **Tasks You'll Complete**: * Create custom SAML application in Google Admin Console * Download and host SAML metadata XML file * Configure service provider details (ACS URL and Entity ID) * Set up attribute mapping for email addresses * Configure user access permissions * Create enterprise connection in Hanko Cloud * Test integration using IdP-initiated flow
## Prerequisites You need your project's SAML Assertion Consumer Service (ACS) URL and the Service Provider (SP) Entity ID. ### Service Provider Entity ID The SP Entity ID for your Hanko project is equal to the API URL of your project. To find the API URL for your project: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Dashboard`. 3. Copy and save the `API URL`. Obtain the API URL from the Hanko Cloud project dashboard ### Service Provider ACS URL To find the Assertion Consumer Service (ACS) URL for your project: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Enterprise connections`. 3. Under `Enterprise connections` find the `Redirect URL` panel. 4. Copy and save the URL. Obtain the Assertion Consumer Service URL in the Hanko Cloud enterprise settings of a project ## Create a Google Workspace application 1. Sign in to the [Google Admin Console](https://admin.google.com). 2. In the left sidebar select `Apps > Web and mobile apps`. 3. Toggle the `Add app` dropdown in the main view. 4. Click `Add custom SAML app`. Create a custom SAML app in the Google Admin Console 5. Provide a name for your app. 6. Click `Continue`. Create a custom SAML app in the Google Admin Console 7. Click `Download Metadata`. You need to download and host this file publicly because Hanko requires access to the metadata file via URL. See [Hosting the SAML XML Metadata file](#hosting-the-saml-xml-metadata-file) for details. 8. Click `Continue`. Download SAML IdP Metadata XML for your application 8. Under `ACS URL` enter your ACS URL (see [Prerequisites - Service Provider ACS URL](#service-provider-acs-url)). 9. Under `Entity ID` enter you project API URL (see [Prerequisites - Service Provider Entity ID](#service-provider-entity-id)). 10. Click `Continue`. Provide Service Provider details 11. In the `Attributes` panel, click `Add Mapping`. Provide Service Provider details 12. Provide the following mapping: | Google Directory Attribute | App attribute | | -------------------------- | -------------------------------------------------------------------- | | `Primary email` | `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress` | 13. Click `Finish`. Create an attribute mapping for the email address 14. You should be redirected to your app's "dashboard". Click the `User access` panel. Configure user access for your application 15. Set the `Service status` to `ON for everyone`. 16. Click `Save`. Configure user access for your application ## Hosting the SAML XML Metadata file Google only provides SAML metadata as a downloadable XML file, but Hanko requires access to metadata files via URL rather than file upload. You must host the downloaded file on a publicly accessible web service (such as AWS S3, Cloudflare R2, or a public website) that Hanko can access. ## Configure an enterprise connection 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Enterprise connections`. 3. Under `Connections`, click `New connection`. Create a new enterprise connection in the Hanko Cloud project settings 4. In the shown modal provide the following data: * A `Name` for the connection. * A `Domain` for the connection. When users authenticate via SAML SSO, the domain of the email address provided as an identifier at the start of an authentication flow must match the domain configured here. * A `Metadata URL`. This is the URL of your [hosted SAML XML Metadata file](#hosting-the-saml-xml-metadata-file). * Select whether you want skip email verification for this provider. 5. Click `Save` to create the connection. Provide name, domain, metadata URL and email verification requirement for a new enterprise connection ## Testing your integration To test your integration via [IdP-initiated](/guides/enterprise-sso/introduction#identity-provider-initiated-sso) flow: 1. Open one of the Google Workspace applications, e.g. Google Calendar. 2. Access the user's available applications in the top navigation. 3. Find your application and click the icon for your application. Test identity provider initiated login via google workspace app (calendar) # Using SAML SSO with Hanko Source: https://docs.hanko.io/guides/enterprise-sso/introduction Learn how SAML SSO enterprise connections work with Hanko.
**Hanko SAML Integration Overview**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide provides a comprehensive overview of SAML SSO enterprise connections, including setup concepts, authentication flows, security considerations, and account provisioning strategies. **Key Technologies**: * SAML 2.0 * XML digital signatures * Identity providers (IdP) * Service providers (SP) * SSO workflows **Prerequisites**: * Basic understanding of authentication concepts * Hanko Cloud account * Familiarity with identity provider terminology * Understanding of enterprise authentication requirements **Tasks You'll Complete**: * Understand SAML authentication flow types * Learn enterprise connection configuration * Explore SP-initiated vs IdP-initiated SSO flows * Configure account provisioning and linking * Review security considerations and limitations * Access provider-specific integration guides
Security Assertion Markup Language (SAML) is an open standard for authentication and authorization that enables secure, single sign-on (SSO) access to applications and services. By allowing identity providers (IdPs) to authenticate users and pass authorization credentials to service providers (SPs), SAML enhances security, reduces password fatigue, and improves user experience. Hanko supports SAML SSO for any IdP compatible with the SAML 2.0 protocol. This guide uses SAML 2.0 terminology. Consult the [glossary](#glossary) for unfamiliar terms. ## Managing enterprise connections A SAML SSO integration requires configuration at the Service Provider (SP, your Hanko project in this case) and the Identity Provider (IdP). ### Adding an enterprise connection To add an enterprise connection to your project: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Enterprise connections`. 3. Under `Connections`, click `New connection`. 4. In the shown modal provide the following data: * A `Name` for the connection. * A `Domain` for the connection. When users authenticate via SAML SSO, the domain of the email address provided as an identifier at the start of an authentication flow must match the domain configured here. * A `Metadata URL`. This must be a URL pointing to a SAML 2.0 Metadata XML file containing the Identity Provider's metadata. Hanko Cloud tenants currently do not support the upload of Metadata XML files. If your Identity Provider (IdP) does not offer a Metadata URL (e.g., Google) and instead only allows downloading a Metadata XML file, you must download this file, host it independently and publicly available, and provide the URL to the file. * Select whether you want skip email verification for this provider. If disabled, the Hanko tenant sends a verification email to the user's email address if no information about the verification status of a user's email address for the provider is discernible from SAML responses. Hanko Cloud tenants currently do not support configuring mappings of SAML attributes from SAML responses to user properties at the Hanko tenant. If your providers' SAML responses can be configured to or do already include a SAML attribute with information about an verification status of an email address in a SAML response's attribute statement, then the tenant will currently ignore it. It is therefore recommended to not skip email verification to prevent hijacking of existing Hanko accounts by bad actors using unverified IdP addresses (see also: [Account provisioning and linking](#account-provisioning-and-linking)) ### Configuring SAML identity providers The configuration required at an IdP varies by provider. While Hanko supports any SAML 2.0-compatible provider, the following providers have been officially tested: * [Auth0](/guides/enterprise-sso/auth0) * [Microsoft Entra ID](/guides/enterprise-sso/entra) * [Google (Workspaces)](/guides/enterprise-sso/google) * [Okta](/guides/enterprise-sso/okta) ## Using enterprise connections Once you have set up a connection, users can authenticate via SAML SSO using either a [Service Provider-initiated SSO](#service-provider-initiated-sso) or an [Identity Provider-initiated SSO](#identity-provider-initiated-sso) flow. The main difference between these two flow types is that in an SP-initiated SSO flow, the authentication process starts when the user attempts to access a service, whereas in an IdP-initiated flow, the user begins the authentication process at the IdP. ### Service provider-initiated SSO The Service Provider-initiated (SP-initiated) flow begins with the Service Provider (SP - your Hanko Cloud tenant acting as the Service Provider) initiating a SAML authentication request when attempting to access your client application, rather than the user directly starting it with the IdP. It will automatically attempt to match the domain of a user's email address provided as an identifier at the start of an authentication to the domain you configured for your connection (see [Managing Enterprise Connections](#managing-enterprise-connections)) and then redirect to the IdP for authentication. ```mermaid theme={null} --- config: showSequenceNumbers: true --- sequenceDiagram participant User as User participant CA as Client Application participant SP as Service Provider (SP)
Hanko participant IdP as Identity Provider (IdP) User->>CA: Request login for
john.doe@example.com CA->>SP: Request login with IdP
for john.doe@example.com SP->>SP: Select provider configured
for domain example.com SP->>IdP: Redirect User to IdP for Authentication IdP->>User: Presents Login Page User->>IdP: Submits Credentials IdP->>IdP: Authenticates User IdP->>SP: Sends SAML Assertion SP->>SP: Validates SAML Assertion opt Email verification for provider is required SP-)User: Send verification email User->>SP: Verify email end SP->>User: Grant access and redirect to client application User->>CA: Access application ``` 1. The User requests access to your application and provides an email address as an identifier. 2. The authentication request is relayed to your Hanko Cloud tenant. 3. The Hanko API (which acts as a Service Provider (SP) in SAML terms) determines the Identity Provider (IdP) for the provided email address' domain. 4. The SP redirects the User to the IdP for authentication. 5. The IdP displays a login page to the User. 6. The User submits their credentials to the IdP. 7. The IdP authenticates the User. 8. Upon successful authentication, the IdP generates and sends a SAML Assertion back to the SP. 9. The SP validates the SAML Assertion. 10. *Optional*: If email verification for the provider is required, the SP sends a verification email to the User's email address. 11. *Optional*: The User verifies his email address. 12. Once validated and optional email verification was performed, the SP grants access and redirects the User to the Client Application. 13. The User accesses the Client Application. ### Identity provider-initiated SSO In an Identity Provider-initiated (IdP-initiated) flow, the user begins at the Identity Provider (IdP), which could be a login portal or a service like Google or Microsoft. After authentication with the IdP the user selects which service or application they want to access. ```mermaid theme={null} --- config: showSequenceNumbers: true --- sequenceDiagram participant User as User participant CA as Client Application participant SP as Service Provider (SP)
Hanko participant IdP as Identity Provider (IdP) User->>IdP: Login with IdP IdP->>IdP: Authenticate User User->>IdP: Request SSO for Client Application IdP->>SP: Send SAML Assertion SP->>SP: Validate SAML Assertion opt Email verification for provider is required SP-)User: Send verification email User->>SP: Verify email end SP->>User: Grant access and redirect to client application User->>CA: Access application ``` 1. The User accesses the IdP and requests a login. 2. The IdP authenticates the user. 3. The user requests access to a specific Client Application or Service. 4. The IdP generates and sends a SAML Assertion to the SP. 5. The SP validates the received SAML Assertion. 6. *Optional*: If email verification for the provider is required, the SP sends a verification email to the User's email address. 7. *Optional*: The User verifies the email address. 8. Upon successful validation, the SP grants the user access to the requested service. 9. The User accesses the Client Application. #### Security considerations An IdP-initiated flow is inherently more insecure than an SP-initiated flow because it allows the IdP to send SAML assertions directly to the SP (so-called *unsolicited* SAML responses) without first verifying that the user actually requested access to the SP. This increases the risk of unauthorized access if the IdP’s response is intercepted or if there is a vulnerability in the IdP, as the SP has no prior context to ensure the user’s intent. To mitigate the risks of IdP-initiated flows: * Hanko ensures that unsolicited SAML responses do not contain an `InResponseTo` attribute (following section `4.1.5 Unsolicited Responses` of the [SAML 2.0 profiles specification](https://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf)). This prevents malicious actors from intercepting a response used in an SP-initiated flow and reusing it in an IdP-initiated flow. * To further mitigate the risk of replay of SAML responses, Hanko keeps track of all IdP-initiated SAML requests to ensure one-time use. Because of the risks of the IdP-initiated it is recommended to use an SP-initiated flow instead. ## Account provisioning and linking On a successful SAML SSO Hanko attempts to link Identity Provider (IdP) accounts to existing Hanko accounts based on e-mail addresses: * If no Hanko account with email address exists, then a new Hanko account is created and the IdP is linked to the newly created account. If you want to prevent this type of automatic account creation for your project, you can disable user self-service account creation and instead manually create or bulk import users through the console. 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > User account`. 3. Find the `Account self-service` section. 4. Use the `Allow Account creation` toggle enable or disable self-service account creation. 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Users`. 3. On the top right, click * `Create new` to manually create a user. * `Import` to bulk import users. See also: [Import and export users](/guides/import-export-users) * If a Hanko account with the same email address exists, Hanko and IdP accounts are linked. IdPs may allow account holders to use unverified email addresses or may not provide any information at all about the verification status of email addresses. This poses a security risk and potentially allows bad actors to hijack existing Hanko accounts associated with the same address. It is therefore recommended to make sure you trust the provider and to not skip email verification for your provider (see: [Managing enterprise connections](#managing-enterprise-connections)) to ensure that only verified third party provider addresses may be used. ## SAML data of Hanko Cloud projects Below you will find configuration data of your project that may be required for integrating with an Identity Provider. | Property | Value | | -------------------------------------- | ---------------------------------------------------------------- | | `Assertion Consumer Service (ACS) URL` | `/saml/callback` | | `Entity ID/Audience URI` | `` | | `Metadata URL (download)` | `/saml/metadata?domain=` | | `Metadata URL (certificate)` | `/saml/metadata?domain=&cert_only=true` | Replace the `` with your project's API URL. You can find the API URL on your project's dashboard in the [Hanko Cloud Console](https://cloud.hanko.io). ## Limitations * **No subdomains**: When authenticating via SAML SSO the domain of a user's email address must exactly match the domain configured for an enterprise connection. If you have configured a domain of `example.com` and a user attempts to authenticate with an email address of `john.doe@subdomain.example.com` then no SAML SSO flow will be triggered but instead the login flow will proceed using any of the authentication methods activated for your tenant. * **Number of enterprise connections**: Every Hanko Cloud project includes one free enterprise connection. Your organization will be charged an additional fee per month per connection. See [Pricing](https://www.hanko.io/pricing) for more details. * **Single Logout (SLO)**: Single Logout (SLO) is currently not supported. ## Glossary | **Term** | **Description** | | | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | | **Assertion** | A statement issued by the Identity Provider (IdP) containing authentication, attribute, and authorization data about a user, used by the Service Provider (SP) to authenticate the user. | | | **Assertion Consumer Service (ACS)** | The endpoint on the Service Provider (SP) that receives the SAML response containing the assertion from the Identity Provider (IdP) and processes it for user authentication. | | | **Attribute** | A piece of information about the user that the Identity Provider (IdP) sends to the Service Provider (SP) within a SAML assertion, such as user roles or group memberships. | | | **AttributeStatement** | A part of the SAML assertion containing user attributes, such as email address, roles, or group memberships, sent from the Identity Provider (IdP) to the Service Provider (SP). | | | **Entity ID** | The Entity ID is a globally unique string assigned to either an Identity Provider (IdP) or a Service Provider (SP). This identifier helps to differentiate different entities in a SAML federation and ensures that the communication is happening between the correct IdP and SP. | | | **Identity Provider (IdP)** | An entity that authenticates users and issues SAML assertions to Service Providers (SPs) for Single Sign-On (SSO). | | | **IdP-initiated Flow** | An authentication flow where the user starts at the Identity Provider (IdP), which sends a SAML response directly to the Service Provider (SP), granting the user access. | | | **Metadata** | A file that describes the configuration of the Identity Provider (IdP) or Service Provider (SP), including URLs, certificates, and supported bindings. | | | **SAML Request** | A request message from the Service Provider (SP) to the Identity Provider (IdP) to initiate authentication, including requests for specific authentication context or user attributes. | | | **SAML Response** | A message from the Identity Provider (IdP) to the Service Provider (SP) that contains the SAML assertion, which includes authentication information about the user. | | | **Service Provider (SP)** | An entity that provides services or resources to users and relies on an Identity Provider (IdP) to authenticate users via SAML assertions. | | | **Single Logout (SLO)** | A mechanism by which a user can log out from all connected systems and service providers in a federated environment with one logout action. | | | **Single Sign-On (SSO)** | A method of authentication that allows a user to access multiple applications with a single set of credentials. SAML is commonly used to implement SSO. | | | **SP-initiated Flow** | An authentication flow where the Service Provider (SP) initiates the authentication request to the Identity Provider (IdP), common when the user accesses a service directly. | | | **Unsolicited SAML Request** | A request sent by the Identity Provider (IdP) to the Service Provider (SP) without the SP first initiating the request. This typically occurs in an IdP-initiated SSO flow. | | # Set up SAML SSO with Okta Source: https://docs.hanko.io/guides/enterprise-sso/okta Learn how to set up enterprise connections in Hanko for customers using Okta as SAML identity provider.
**Hanko Okta SAML Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to configure Okta as a SAML identity provider for your Hanko project, enabling secure single sign-on authentication for enterprise users managed by Okta. **Key Technologies**: * SAML 2.0 * XML digital signatures * Okta identity provider * SAML assertions **Prerequisites**: * Active Okta account with admin access * Access to Okta Administrative Console * Hanko Cloud project * Basic understanding of SAML authentication protocols **Tasks You'll Complete**: * Create SAML app integration in Okta * Configure single sign-on URL and audience URI * Set up attribute statements for email mapping * Obtain metadata URL from Okta application * Assign users to the application * Create enterprise connection in Hanko Cloud * Test integration using IdP-initiated flow
## Prerequisites You need your project's SAML Assertion Consumer Service (ACS) URL and the Service Provider (SP) Entity ID. ### Service Provider Entity ID The SP Entity ID for your Hanko project is equal to the API URL of your project. To find the API URL for your project: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Dashboard`. 3. Copy and save the `API URL`. Obtain the API URL from the Hanko Cloud project dashboard ### Service Provider ACS URL To find the Assertion Consumer Service (ACS) URL for your project: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Enterprise connections`. 3. Under `Enterprise connections` find the `Redirect URL` panel. 4. Copy and save the URL. Obtain the Assertion Consumer Service URL in the Hank Cloud enterprise settings of a project ## Create an Okta application 1. Create an account at [Okta](https://okta.com). Once registered, access the Okta Administration console at `https://-admin.okta.com`. 2. Select `Applications > Applications` in the left sidebar. 3. Click `Create App Integration`. Create app integration in the Okta Administrative Console's Applications settings 4. In the shown modal select `SAML` as the sign-in method. 5. Click `Next`. Select SAML as sign-in method for new app integration 6. In the `Create SAML Integration` wizard, provide an `App name`. 7. Click `Next`. Configure basic properties like app name and logo in SAML integration wizard 8. Under `Single sign-on URL` enter your ACS URL (see [Prerequisites - Service Provider ACS URL](#service-provider-acs-url)). 9. Under `Audience URI (SP Entity ID)` enter you project API URL (see [Prerequisites - Service Provider Entity ID](#service-provider-entity-id)). Configure Hanko project ACS URL as Single sign-on URL and API URL as Audience URI in SAML integration wizard 10. Scroll down and find the `Attribute statements` panel. Under `Name` enter `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`. 11. Under `Name format` select `URI Reference` 12. Under `Value` select `user.email`. 13. Click `Next`. Configure email address attribute mapping in SAML integration wizard 14. Provide feedback on the next screen of the configuration wizard and click `Finish`. 15. Select `Sign On` in the top tab navigation. 16. In the `Settings > Sign-on methods > SAML 2.0` panel find the `Metadata URL` in the `Metadata details` and copy it. You need this for configuring the enterprise connection with Hanko. Configure email address attribute mapping in SAML integration wizard ### Assign users to your application To enable users to log in, you need to assign users to the application. To assign users: 1. Select `Applications > Applications` in the left sidebar. 2. Click `Assign Users to Apps`. Assign users to apps in Applications settings 3. Select the app you want to assign users to. 4. Select users you want to assign to the app. 5. Click `Next`. Select which users should be assigned to which app 6. Review your assignments and click `Confirm assignments`. ## Configure an enterprise connection 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Enterprise connections`. 3. Under `Connections`, click `New connection`. Create a new enterprise connection in the Hanko Cloud project settings 4. In the shown modal provide the following data: * A `Name` for the connection. * A `Domain` for the connection. When users authenticate via SAML SSO, the domain of the email address provided as an identifier at the start of an authentication flow must match the domain configured here. * A `Metadata URL`. This is the URL you copied in step 16 in [Create an Okta application](#create-an-okta-application). * Select whether you want skip email verification for this provider. 5. Click `Save` to create the connection. Provide name, domain, metadata URL and email verification requirement for a new enterprise connection ## Testing your integration To test your integration via [IdP-initiated](/guides/enterprise-sso/introduction#identity-provider-initiated-sso) flow: 1. On the top right click the user dropdown. 2. Click `My settings`. Access user Okta user profile 3. In your end-user profile select `My Apps` in the left sidebar. 4. Find your app and click its icon. Access user's assigned applications in Okta user profile # Hanko Elements Auth component guide Source: https://docs.hanko.io/guides/hanko-elements/auth-component A Web Component that handles user login and user registration.
**Hanko Elements Auth Component Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to implement the `` web component, which provides a unified authentication interface that handles both user login and registration flows in a single component. You'll learn how to integrate this versatile component into various frameworks and customize its behavior for different use cases. **Key Technologies**: * Hanko Elements * Web Components * JavaScript/TypeScript * React, Vue, Svelte * Next.js, Nuxt, SvelteKit * CSS customization * Passkeys * OAuth SSO * Modern authentication methods **Prerequisites**: * Basic knowledge of frontend development, HTML/JavaScript, your chosen framework * Active Hanko account with API access **Tasks You'll Complete**: * Install and register the Hanko Elements package * Configure the `` component in your application * Implement the component across different frameworks (React, Vue, Svelte) * Set up event handlers for authentication state changes * Configure component attributes for prefilled values and language settings * Handle both login and registration flows in an unified interface
## Use case The `` component provides a complete authentication solution that combines both login and registration functionality in a single interface. This component is ideal for applications that want to streamline their authentication process without needing separate routes or pages for different authentication flows. The component automatically handles transitions between login and registration views, providing a seamless user experience throughout the entire authentication process. If you want to create a dedicated Login page: \ [try out the`` component](/guides/hanko-elements/login-component). If you want to create a dedicated Registration page: \ [try out the `` component](/guides/hanko-elements/register-component) . ## Features | | | | ------------------------ | ------------------------------------------------------------------------------------------- | | **Login + Registration** | Seamlessly handles both flows in one component. | | **Passkeys** | Enables passwordless login with modern device credentials. | | **Passcodes** | Useful for email-based login and verification workflows. | | **2FA** | Users can use a TOTP app or security keys. | | **OAuth SSO** | Allows users to log in using third-party identity providers (e.g., Google, Apple). | | **SAML SSO** | Allows users to log in using SAML identity providers (e.g., Entra, Okta, Google Workspace). | | **Passwords** | Supports traditional password-based login for broader accessibility. | ## Usage ### Markup ```html theme={null} ``` ### Attributes | Name | Description | | -------------------- | -------------------------------------------------------------- | | `prefilled-email` | Used to prefill the email input field | | `prefilled-username` | Used to prefill the username input field | | `lang` | Used to specify the language of the content within the element | | `mode` | Specify the starting flow, either `registration` or `login` | ### Adding `` component The following examples show how to integrate the `` component in different full-stack and frontend frameworks. #### Full stack ```jsx components/HankoAuth.tsx theme={null} "use client" import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export default function HankoAuth() { useEffect(() => { register(hankoApi) .catch((error) => { // handle error }); }, []); return ( ); } ``` ```jsx components/HankoAuth.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export default function HankoAuth() { useEffect(() => { register(hankoApi) .catch((error) => { // handle error }); }, []); return ( ); } ``` ```html login.vue theme={null} ``` ```html HankoAuth.svelte theme={null} ``` #### Frontend ```jsx components/HankoAuth.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.REACT_APP_HANKO_API_URL; export default function HankoAuth() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```jsx components/HankoAuth.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; export default function HankoAuth() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```html HankoAuth.vue theme={null} ``` ```html HankoProfile.svelte theme={null} ``` ```html login.html theme={null} ``` You should see an interface similar to this 👇 sign-up For more detailed instructions on integrating `` component with your favorite frameworks, navigate to [quickstart guides](/quickstarts/fullstack). # Customize appearance of Hanko Elements Source: https://docs.hanko.io/guides/hanko-elements/customize-appearance This guide will walk you through the UI customization of Hanko Elements components.
**Hanko Elements Appearance Customization Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to customize the visual appearance of Hanko web components (``, ``, ``, and ``) to match your application's design and branding. You'll learn to use CSS variables and CSS Shadow Parts to create a cohesive user interface that aligns with your application's style. **Key Technologies**: * Hanko Elements * CSS variables * CSS Shadow Parts * Web Components Shadow DOM * CSS styling * Responsive design * Frontend theming techniques **Prerequisites**: * Basic knowledge of CSS styling, web components, and frontend development * Understanding of CSS variables and Shadow DOM concepts will be helpful **Tasks You'll Complete**: * Configure CSS variables to customize colors, fonts, and layout * Use CSS Shadow Parts to target specific component elements * Implement custom styling for different component states * Create responsive designs that work across devices * Apply consistent branding across all Hanko components * Learn advanced styling techniques for web component customization
## CSS variables You can use CSS variables to customize the appearance of `hanko-auth` and `hanko-profile` elements to match your design requirements. The complete list of available CSS variables and their default values is shown below: ```css theme={null} hanko-auth, hanko-profile { /* Color Scheme */ --color: #333333; --color-shade-1: #8f9095; --color-shade-2: #e5e6ef; --brand-color: #506cf0; --brand-color-shade-1: #6b84fb; --brand-contrast-color: white; --background-color: white; --error-color: #e82020; --link-color: #506cf0; /* Font Styles */ --font-weight: 400; --font-size: 16px; --font-family: sans-serif; /* Border Styles */ --border-radius: 8px; --border-style: solid; --border-width: 1px; /* Item Styles */ --item-height: 34px; --item-margin: 0.5rem 0; /* Container Styles */ --container-padding: 30px; --container-max-width: 410px; /* Headline Styles */ --headline1-font-size: 24px; --headline1-font-weight: 600; --headline1-margin: 0 0 1rem; --headline2-font-size: 16px; --headline2-font-weight: 600; --headline2-margin: 1rem 0 0.5rem; /* Divider Styles */ --divider-padding: 0 42px; --divider-visibility: visible; /* Link Styles */ --link-text-decoration: none; --link-text-decoration-hover: underline; /* Input Styles */ --input-min-width: 14em; /* Button Styles */ --button-min-width: max-content; } ``` ## CSS Shadow Parts In addition to CSS variables, you can use the `::part` selector to customize specific elements within the components. Note that shadow parts only work when the web components are attached to the shadow DOM, which is the default behavior. You can enable the shadow DOM for the components using the following code: ```js theme={null} register("https://hanko.yourdomain.com", { shadow: true }); // equals register("https://hanko.yourdomain.com"); ``` | Name | Description | | ------------------ | ------------------------------------------------------------- | | `container` | the UI container | | `headline1` | the "h1" headlines | | `headline2` | the "h2" headlines | | `paragraph` | the paragraph elements | | `button` | every button element | | `primary-button` | the primary button | | `secondary-button` | the secondary button on the email login page | | `input` | every input field | | `text-input` | every input field not used for passcodes | | `passcode-input` | the passcode input fields | | `link` | the links in the footer section | | `error` | the error message container | | `error-text` | the error message | | `divider` | the horizontal divider on the login page | | `divider-text` | the divider text | | `divider-line` | the line before and after the `divider-text` | | `form-item` | the container of a form item, e.g. an input field or a button | ### Examples The following examples show how to apply custom styles to specific shadow parts: #### Stacking `hanko-auth` component fields vertically This example demonstrates how to force the input fields and buttons within the `hanko-auth` component to stack vertically. The `::part(form-item)` selector targets the `form-item` shadow part within the `hanko-auth` component, which is applied using the tag name. ```html theme={null} ``` #### Modifying the main headlines for Hanko components This example shows how to adjust the main headlines for all hanko components by targeting the `headline1` shadow part. The `.hankoComponent::part(headline1)` selector applies the styles to the `headline1` shadow part within elements that have the `hankoComponent` class. ```html theme={null} ``` #### Applying box shadow on button of `hanko-auth` component In this example, a box shadow is applied to the `button` shadow part of the `hanko-auth` component when hovering over it. The `#hankoAuth::part(button):hover` selector targets the button shadow part within the `hanko-auth` component using the ID selector `#hankoAuth` and applies the styles when the `:hover` pseudo-class is active. ```html theme={null} ``` For more examples and design inspiration, check out our blog post, [Make Hanko Components Shine](https://dev.to/hanko/make-hanko-components-shine-1d61). # Events component guide Source: https://docs.hanko.io/guides/hanko-elements/events-component A Web Component that allows to bind event handlers to certain events, without displaying UI elements.
**Hanko Elements Events Component Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to use the `` web component, which provides a way to listen for authentication events without displaying any UI elements. You'll learn how to bind event handlers to respond to authentication state changes in your application. **Key Technologies**: * Hanko Elements * Web Components * JavaScript event handling * Authentication events * Frontend SDK integration * Event-driven architecture **Prerequisites**: * Basic knowledge of JavaScript event handling, web components, and frontend development * Understanding of authentication flows and event-driven programming will be helpful **Tasks You'll Complete**: * Implement the `` component in your application * Bind event handlers to authentication events * Handle session creation, expiration, and user state changes * Integrate event handling with your application's navigation and state management * Use events for custom authentication flows and user experience enhancements
You can subscribe to events with the `` and `` components in the same way. You can also bind event handlers using the `frontend-sdk` (see the next section). ## Usage ### Markup ```html theme={null} ``` # Hanko Elements guide Source: https://docs.hanko.io/guides/hanko-elements/introduction Hanko Elements are Web Components that can be used to quickly add registration, login, and profile settings functionality to web apps.
**Hanko Elements introduction guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide introduces Hanko Elements, a collection of pre-built web components that provide modern authentication functionality. You'll learn about the available components, their features, and how to get started with integrating the components in your applications. **Key Technologies**: * Hanko Elements * Web Components * JavaScript/TypeScript * Passkeys * OAuth SSO * 2FA authentication * CSS customization * Internationalization * Modern web frameworks integration **Prerequisites**: * Basic knowledge of frontend development, HTML/JavaScript, and web components * Familiarity with your chosen frontend framework and an active Hanko account **Tasks You'll Complete**: * Understand the available Hanko web components and their use cases * Install and configure Hanko Elements in your project * Register web components and configure authentication options * Implement basic authentication flows using pre-built components * Set up event handling for authentication state management * Explore customization and internationalization options
## Components overview A Web Component that handles user login. A Web Component that handles user registration. User login and registration flows combined into a single Web Component. A Web Component that allows users to manage their account. ## Installation Add Hanko Elements to your project using your preferred package manager or CDN: ```bash npm theme={null} npm install @teamhanko/hanko-elements ``` ```bash pnpm theme={null} pnpm add @teamhanko/hanko-elements ``` ```bash yarn theme={null} yarn add @teamhanko/hanko-elements ``` ## Usage To use Hanko, import and call the `register()` function from the `hanko-elements` module. This enables the web components throughout your application. For proper functionality, add the `` element to enable user authentication, and configure the "onSessionCreated" event handler to define post-authentication behavior, such as page redirection. Detailed implementation steps are provided in the following sections. ### Importing the module If you installed via a package manager, you can import the `register()` function from the `@teamhanko/hanko-elements` package in your TypeScript or JavaScript file: ```js theme={null} import { register } from "@teamhanko/hanko-elements"; ``` For CDN usage, include a `script` tag with the import statement referencing the CDN-hosted `hanko-elements` package URL: ```html theme={null} ``` ### Registering the Web Components After importing the `register()` function, call it with your Hanko API URL to register the Hanko elements with the browser's `CustomElementRegistry`: ```js theme={null} const { hanko } = await register("YOUR_HANKO_API_URL"); ``` You can provide configuration options to customize the behavior and appearance of the components: ```js theme={null} const defaultOptions = { shadow: true, // Set to false if you do not want the web component to be attached to the shadow DOM. injectStyles: true, // Set to false if you do not want to inject any default styles. enablePasskeys: true, // Set to false if you do not want to display passkey-related content. hidePasskeyButtonOnLogin: false, // Hides the button to sign in with a passkey on the login page. translations: null, // Additional translations can be added here. English is used when the option is not // present or set to `null`, whereas setting an empty object `{}` prevents the elements // from displaying any translations. translationsLocation: "/i18n", // The URL or path where the translation files are located. fallbackLanguage: "en", // The fallback language to be used if a translation is not available. storageKey: "hanko", // The name of the cookie the session token is stored in and the prefix / name of local storage keys cookieDomain: undefined, // The domain where the cookie set from the SDK is available. When undefined, // defaults to the domain of the page where the cookie was created. cookieSameSite: "lax", // Specify whether/when cookies are sent with cross-site requests. sessionCheckInterval: 30000, // Interval for session validity checks in milliseconds. Must be greater than 3000 (3s). sessionTokenLocation: "cookie", // Specify where the session token should be stored. Either `cookie` or `sessionStorage`. }; const { hanko } = await register("YOUR_HANKO_API_URL", defaultOptions); ``` #### Cookie options * If `cookieSameSite` is set to `none` then your application must be served through HTTPS. The `Secure` attribute is automatically set to true if your application uses HTTPS. * If you want cookies to be available on subdomains, you must set your `cookieDomain` to your domain prefixed with a `.`. For example, if your frontend application is running on `myapp.com` and you want cookies to be available on `api.myapp.com`, then the `cookieDomain` value should be `.myapp.com`. ### Embedding the Web Components After completing the above steps, you can add the web components to your application's markup. Here's a basic example: ```html theme={null} ``` ## Advanced guides } href="/guides/hanko-elements/customize-appearance" > Style Hanko Elements Web Components to match your app's design. } href="/guides/hanko-elements/translations" > Support for multiple languages and translation options for a global user base. # Hanko Elements Login component guide Source: https://docs.hanko.io/guides/hanko-elements/login-component A Web Component that handles user login.
**Hanko Elements Login Component Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to implement the `` web component, which provides a dedicated login interface for existing users. You'll learn how to integrate this component for applications that require separate login and registration flows or controlled-access scenarios. **Key Technologies**: * Hanko Elements * Web Components * JavaScript/TypeScript * React, Vue, Svelte * Next.js, Nuxt, SvelteKit * Passkeys * OAuth SSO * 2FA authentication * Session management **Prerequisites**: * Basic knowledge of frontend development, HTML/JavaScript, your chosen framework * Active Hanko account with API access **Tasks You'll Complete**: * Install and register the Hanko Elements package * Configure the `` component for login-only flows * Implement the component across different frameworks (React, Vue, Svelte) * Set up event handlers for successful login events * Configure component attributes for prefilled values and language settings * Handle authentication state changes and navigation
## Use case The `` component is designed for dedicated login interfaces and intentionally excludes registration functionality, unlike ``. This makes it ideal for controlled-access applications such as enterprise systems, internal tools, or invitation-based platforms where user registration needs to be restricted. If you want to Combine Login and Register on the same page: \ [try out the`` component](/guides/hanko-elements/auth-component). If you want to create a dedicated Registration page: \ [try out the `` component](/guides/hanko-elements/register-component) . ## Features | | | | ------------- | ------------------------------------------------------------------------------------------- | | **Login** | Allows users to securely log in to their existing accounts. | | **Passkeys** | Enables passwordless login with modern device credentials. | | **Passcodes** | Useful for email-based login and verification workflows. | | **2FA** | Users can use a TOTP app or security keys. | | **OAuth SSO** | Allows users to log in using third-party identity providers (e.g., Google, Apple). | | **SAML SSO** | Allows users to log in using SAML identity providers (e.g., Entra, Okta, Google Workspace). | | **Passwords** | Supports traditional password-based login for broader accessibility. | ## Usage ### Markup ```html theme={null} ``` ### Attributes | Name | Description | | -------------------- | -------------------------------------------------------------- | | `prefilled-email` | Used to prefill the email input field | | `prefilled-username` | Used to prefill the username input field | | `lang` | Used to specify the language of the content within the element | ### Adding `` component The following examples show how to integrate the `` component in different full-stack and frontend frameworks. #### Full stack ```jsx components/HankoLogin.tsx theme={null} "use client" import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export default function HankoLogin() { useEffect(() => { register(hankoApi) .catch((error) => { // handle error }); }, []); return ( ); } ``` ```jsx components/HankoLogin.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export default function HankoLogin() { useEffect(() => { register(hankoApi) .catch((error) => { // handle error }); }, []); return ( ); } ``` ```html login.vue theme={null} ``` ```html HankoLogin.svelte theme={null} ``` #### Frontend ```jsx components/HankoLogin.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.REACT_APP_HANKO_API_URL; export default function HankoLogin() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```jsx components/HankoLogin.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; export default function HankoLogin() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```html HankoAuth.vue theme={null} ``` ```html HankoLogin.svelte theme={null} ``` ```html login.html theme={null} ``` You should see an interface similar to this 👇 sign-up For more detailed instructions on integrating `` component with your favorite frameworks, navigate to [quickstart guides](/quickstarts/fullstack). # Hanko Elements Profile component Source: https://docs.hanko.io/guides/hanko-elements/profile-component A Web Component that allows users to manage their account and security settings.
**Hanko Elements Profile Component Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to implement the `` web component, which provides a comprehensive user profile management interface. Users can manage their email addresses, passwords, MFA credentials, passkeys, and active sessions through this component. **Key Technologies**: * Hanko Elements * Web Components * JavaScript/TypeScript * React, Vue, Svelte * Next.js, Nuxt, SvelteKit * User profile management * Session management * Account security features **Prerequisites**: * Basic knowledge of frontend development, HTML/JavaScript, your chosen framework * Authenticated user sessions * Active Hanko account with API access **Tasks You'll Complete**: * Install and register the Hanko Elements package * Configure the `` component for user profile management * Implement the component across different frameworks (React, Vue, Svelte) * Enable users to manage email addresses, passwords, and passkeys * Set up session management and security features * Configure language settings and component customization
## Features | | | | ---------------------- | -------------------------------------------------------- | | **Email settings** | Add more email addresses, change and delete them. | | **Password settings** | Change or delete your password (if enabled). | | **Passkey settings** | Add new passkeys, rename or delete them. | | **2FA settings** | Toggle Two-factor authentication and manage 2FA methods. | | **Session Management** | List and revoke active sessions across devices. | ## Usage ### Markup ```html theme={null} ``` ### Attributes | Name | Description | | ------ | -------------------------------------------------------------- | | `lang` | Used to specify the language of the content within the element | ### Adding `` component The following examples show how to integrate the `` component in different full-stack and frontend frameworks. #### Full stack ```jsx components/HankoProfile.jsx theme={null} "use client" import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export default function HankoProfile() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```jsx components/HankoProfile.jsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export default function HankoProfile() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```html profile.vue theme={null} ``` ```html HankoProfile.svelte theme={null} ``` #### Frontend ```jsx components/HankoProfile.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.REACT_APP_HANKO_API_URL; export default function HankoProfile() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```jsx components/HankoProfile.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; export default function HankoProfile() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```html HankoProfile.vue theme={null} ``` ```html HankoProfile.svelte theme={null} ``` ```html profile.html theme={null} ``` You should see an interface similar to this 👇 profile-page For more detailed instructions on integrating `` component with your favorite frameworks, navigate to [quickstart guides](/quickstarts/fullstack). # Hanko Elements Registration component Source: https://docs.hanko.io/guides/hanko-elements/register-component A Web Component that handles user registration.
**Hanko Elements Registration Component Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to implement the `` web component, which provides a dedicated user registration interface for creating new accounts. You'll learn how to integrate this component for applications that require separate registration flows or controlled onboarding processes. **Key Technologies**: * Hanko Elements * Web Components * JavaScript/TypeScript * React, Vue, Svelte * Next.js, Nuxt, SvelteKit * User registration * Passkeys * OAuth SSO * Account creation workflows **Prerequisites**: * Basic knowledge of frontend development, HTML/JavaScript, your chosen framework * Active Hanko account with API access **Tasks You'll Complete**: * Install and register the Hanko Elements package * Configure the `` component for registration-only flows * Implement the component across different frameworks (React, Vue, Svelte) * Set up event handlers for successful registration events * Configure component attributes for prefilled values and language settings * Handle account creation and post-registration navigation
## Use case The `` component is perfect for creating dedicated user registration flows in modern web applications. It provides a secure, flexible way to onboard new users with minimal setup—eliminating the need to build custom UI or manage complex authentication logic. If you want to Combine Login and Register on the same page: \ [try out the`` component](/guides/hanko-elements/auth-component). If you want to create a dedicated Login page: \ [try out the`` component](/guides/hanko-elements/login-component). ## Features | | | | ------------- | ------------------------------------------------------------------------------------------------------ | | **Register** | Allows users to create new accounts. | | **Passkeys** | Enables passwordless login with modern device credentials. | | **Passcodes** | Useful for email-based login and verification workflows. | | **2FA** | Users can use a TOTP app or security keys. | | **OAuth SSO** | Allows users to create an account using third-party identity providers (e.g., Google, Apple). | | **SAML SSO** | Allows users to create an account using SAML identity providers (e.g., Entra, Okta, Google Workspace). | | **Passwords** | Supports traditional password-based login for broader accessibility. | ## Usage ### Markup ```html theme={null} ``` ### Attributes | Name | Description | | -------------------- | -------------------------------------------------------------- | | `prefilled-email` | Used to prefill the email input field | | `prefilled-username` | Used to prefill the username input field | | `lang` | Used to specify the language of the content within the element | ### Adding `` component The following examples show how to integrate the `` component in different full-stack and frontend frameworks. #### Full stack ```jsx components/HankoRegister.tsx theme={null} "use client" import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export default function HankoRegister() { useEffect(() => { register(hankoApi) .catch((error) => { // handle error }); }, []); return ( ); } ``` ```jsx components/HankoRegister.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export default function HankoRegister() { useEffect(() => { register(hankoApi) .catch((error) => { // handle error }); }, []); return ( ); } ``` ```html register.vue theme={null} ``` ```html HankoRegister.svelte theme={null} ``` #### Frontend ```jsx components/HankoRegister.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.REACT_APP_HANKO_API_URL; export default function HankoRegister() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```jsx components/HankoRegister.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; export default function HankoRegister() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` ```html HankoRegister.vue theme={null} ``` ```html HankoRegister.svelte theme={null} ``` ```html Register.html theme={null} ``` You should see an interface similar to this 👇 sign-up For more detailed instructions on integrating `` component with your favorite frameworks, navigate to [quickstart guides](/quickstarts/fullstack). # Hanko Elements internationalization (i18n) guide Source: https://docs.hanko.io/guides/hanko-elements/translations Hanko Elements support multiple languages and translations can be modified to alter headlines, labels, descriptions and all other texts displayed in Hanko Elements.
**Hanko Elements Translations Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to implement internationalization (i18n) for Hanko web components, including setting up multiple languages, customizing translations, and configuring language preferences. You'll learn to provide a localized authentication experience for users worldwide. **Key Technologies**: * Hanko Elements * Internationalization (i18n) * Translation management * Language configuration * Web Components localization * Multilingual user interfaces **Prerequisites**: * Basic knowledge of internationalization concepts, frontend development, and Hanko Elements setup * Understanding of JSON file structures will be helpful **Tasks You'll Complete**: * Configure default language settings for Hanko components * Install and import additional language translations * Customize existing translations to match your application's tone * Create new translations for unsupported languages * Set up external translation files for dynamic language loading * Configure fallback languages for incomplete translations * Implement language switching in your authentication flows
## Default behavior The `hanko-elements` package includes English translations by default, so the `lang` attribute can be omitted. Script ```js theme={null} register("YOUR_HANKO_API_URL"); ``` Markup ```html theme={null} ``` ## Installing additional translations Translations are currently available for the following languages: | Value | Language | | ------- | -------------------- | | `bn` | Bengali (Bangla) | | `de` | German | | `en` | English | | `fr` | French | | `it` | Italian | | `pt-BR` | Brazilian Portuguese | | `zh` | Chinese | You can import them individually: ```js theme={null} // Replace the paths below with // "https://cdn.jsdelivr.net/npm/@teamhanko/hanko-elements/dist/i18n/{en|de|all|...}.js" // if you're using CDN. import { bn } from "@teamhanko/hanko-elements/i18n/bn"; import { de } from "@teamhanko/hanko-elements/i18n/de"; import { en } from "@teamhanko/hanko-elements/i18n/en"; import { fr } from "@teamhanko/hanko-elements/i18n/fr"; import { it } from "@teamhanko/hanko-elements/i18n/it"; import { ptBR } from "@teamhanko/hanko-elements/i18n/ptBR"; import { zh } from "@teamhanko/hanko-elements/i18n/zh"; ``` Or import all translations at once: ```js theme={null} import { all } from "@teamhanko/hanko-elements/i18n/all"; ``` After importing, provide the translations through the `register()` function: ```js theme={null} register("https://hanko.yourdomain.com", { translations: { bn, de, en, fr, it, ptBR, zh } }); // or register("https://hanko.yourdomain.com", { translations: all }); ``` You can now set the `lang` attribute of the element to the desired language: ```html theme={null} ``` In contrast to the named import of the translation object for Brazilian Portuguese ("ptBR"), the `lang` attribute value must be provided as "pt-BR". Otherwise the language is not recognized by the backend and outgoing emails will default to English. ## Modifying translations You can modify existing translations as follows: ```js theme={null} import { en } from "@teamhanko/hanko-elements/i18n/en"; en.errors.somethingWentWrong = "Aww, snap!"; register("YOUR_HANKO_API_URL", { translations: { en } }); ``` ## Adding new translations To create a new translation, pass an object that implements (or partially implements) the `Translation` interface. Script ```js theme={null} import { all } from "@teamhanko/hanko-elements/i18n/all"; import { Translation } from "@teamhanko/hanko-elements"; // if you're using typescript const myLang: Translation = {...} register("YOUR_HANKO_API_URL", {translations: {...all, myLang}}); ``` Markup ```html theme={null} ``` ## Using external translation files For languages provided via the element's lang attribute, or via the fallback language option, that are not included in the object passed to the `translations` option, the component will fetch a JSON file from the location specified by the `translationsLocation` option. For example, if "en" is missing due to an empty object being passed, as shown in the example below, the component will fetch a file named `/i18n/en.json`. Script ```js theme={null} register("https://hanko.yourdomain.com", { translations: {}, // An empty object, so even the default "en" translation won't be available. translationsLocation: "/i18n", // A public folder containing language files, e.g., "en.json". }); ``` Markup ```html theme={null} ``` ## Fallback language The `fallbackLanguage` option is used to specify a fallback language for the web components when translations are missing or incomplete for a particular language. By setting the `fallbackLanguage` option to a valid language string like "en" or "de", the missing translation strings will be automatically retrieved from the specified fallback language. When the translation for the specified `fallbackLanguage` is not available in the `translations` option, the web components will attempt to fetch it from an external file. Script ```js theme={null} import { en } from "@teamhanko/hanko-elements/i18n/en"; import { Translation } from "@teamhanko/hanko-elements"; const symbols: Partial = { labels: { continue: "➔" }, }; register("https://hanko.yourdomain.com", { fallbackLanguage: "en", translations: { en, symbols }, }); ``` Markup ```html theme={null} ``` ## Translation of outgoing emails If you use Hanko Elements the language supplied to the `lang` attribute of any of the components is also used to convey to the Hanko API the language to use for outgoing emails. If you have disabled email delivery through Hanko and configured a webhook for the `email.send` event, the value for the `lang` attribute is reflected in the JWT payload of the token contained in the webhook request in the `language` claim. If you do not use Hanko Elements but use the Hanko Frontend SDK to build your own UI you can provide a `lang` [option](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/HankoOptions.html) when instantiating the main `Hanko` [client](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/Hanko.html). Again, if you choose to opt out of email delivery by Hanko and subscribe to the `email.send` event via webhook, the value used as the argument is reflected in the JWT payload of the token contained in the webhook request in the `language` claim. If you do not use the Hanko frontend SDK but communicate with the Hanko API directly, then you must supply an `X-Language` header to requests targeting the Flow API endpoints ([`/registration`](https://docs.hanko.io/api-reference/flow/registration), [`/login`](https://docs.hanko.io/api-reference/flow/login), [`/profile`](https://docs.hanko.io/api-reference/flow/profile)). # Using the Hanko Frontend SDK Source: https://docs.hanko.io/guides/hanko-elements/using-frontend-sdk The following examples will cover some common use-cases for the `hanko-frontend-sdk` instance returned by the `register()` function, but please take a look into the [frontend-sdk docs](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/) for details.
**Hanko Elements Frontend SDK Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to use the Hanko Frontend SDK directly for advanced authentication workflows and custom implementations. You'll learn to handle authentication events, manage user sessions, and perform common operations without relying solely on web components. **Key Technologies**: * Hanko Frontend SDK * JavaScript/TypeScript * Authentication events * Session management * JWT handling * User management * Custom authentication flows **Prerequisites**: * Basic knowledge of JavaScript/TypeScript, authentication concepts, event handling, and Hanko Elements setup * Understanding of JWT tokens and session management will be helpful **Tasks You'll Complete**: * Create and configure a Hanko Frontend SDK instance * Implement event listeners for authentication state changes * Handle session creation, expiration, and user logout events * Perform common operations like session validation and user data retrieval * Manage authentication tokens and user sessions * Build custom authentication flows using the SDK methods
You can create a `hanko-frontend-sdk` instance without registering the web components: ```js theme={null} import { Hanko } from "@teamhanko/hanko-elements"; const hanko = new Hanko("YOUR_HANKO_API_URL"); ``` ## Events You can bind callbacks to different custom events using the SDK's event listener functions. The callback function will be called when the event occurs, and an object containing event details will be passed to it. ### Session created Triggered after a session has been created and the user has completed any additional steps (e.g., passkey registration or password recovery). It will also be triggered when the user logs in via another browser window. You can use this event to obtain the JWT. ```js theme={null} hanko.onSessionCreated(({ claims }) => { console.info("Session created with JWT claims:", claims); // Redirect to a protected page }); ``` ### Session expired Triggered when the session has expired, or when the session has been removed in another browser window because the user has logged out or deleted their account. ```js theme={null} hanko.onSessionExpired(() => { console.log("Session expired, redirecting to login"); // Redirect to a login page or show the `` element. }); ``` ### User logged out Triggered when the user actively logs out. In other browser windows, a "hanko-session-expired" event will be triggered at the same time. ```js theme={null} hanko.onUserLoggedOut(() => { console.log("User logged out successfully"); // Redirect to a login page or show the `` element. }); ``` ### User deleted Triggered when the user has deleted their account. In other browser windows, a `hanko-session-expired` event will be triggered at the same time. ```js theme={null} hanko.onUserDeleted(() => { console.log("User account deleted"); // Redirect to a login page or show the `` element. }); ``` ## Common operations The SDK provides functions that simplify interaction with the Hanko API. Here are some common operations: Get the session validity and JWT claims: ```js theme={null} const session = await hanko.validateSession(); console.log("Session valid:", session.is_valid, "Claims:", session.claims); ``` Retrieve the session token: ```js theme={null} const token = hanko.getSessionToken(); console.log("Session token:", token); ``` Get the user data: ```js theme={null} const user = await hanko.getCurrentUser(); console.log("User profile:", user.user_id, user.emails); ``` Log out the user: ```js theme={null} await hanko.logout(); console.log("User logged out"); ``` To learn about error handling and other SDK capabilities, check out the [frontend-sdk docs](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/). # Migrate Users from Firebase Source: https://docs.hanko.io/guides/import_export/firebase Learn how to migrate users exported from Firebase with the Firebase CLI to Hanko. ## Overview Hanko supports migrating users from Firebase while allowing them to continue signing in with their existing passwords. During migration, user accounts exported from Firebase are converted into a format that can be imported into Hanko. Password information is preserved in a way that enables Hanko to verify Firebase Scrypt password hashes during authentication, eliminating the need for users to reset their passwords after migration. ## How It Works The migration consists of four steps: 1. Export users from Firebase 2. Export your Firebase project's password hash parameters 3. Convert the exported users into Hanko import data 4. Import the converted users into Hanko After completing these steps, you can verify the migration by signing in with an imported user. ## Prerequisites Before starting, make sure you have: * A Firebase project with Authentication enabled * The [Firebase CLI](https://firebase.google.com/docs/cli#install_the_firebase_cli) installed and authenticated Depending on your preferred execution method for the conversion of Firebase users you also need one of the following sets of prerequisites: * [Docker](https://www.docker.com/) installed and running * [Go](https://go.dev/) (1.21+ recommended) * [Git](https://git-scm.com/) (to clone the Hanko repository) * the cloned [Hanko repository](https://github.com/teamhanko/hanko): ```bash theme={null} git clone https://github.com/teamhanko/hanko.git cd hanko ``` ## Step 1. Export users from Firebase In the [Firebase Console](https://console.firebase.google.com) select the project you want to import users from. Find your project's ID on the top of the main `Project Overview`. Export your Firebase users using the Firebase CLI's [`auth:export`](https://firebase.google.com/docs/cli/auth#auth-export) command: ```bash theme={null} firebase auth:export firebase-users.json --project ``` This generates a file containing Firebase users including their password hashes. ## Step 2. Export Firebase hash config 1. In the Firebase console, go to the `Authentication` section of your project. 2. Click the three vertical dots on the top right of the users table and select `Password hash parameters` Get Firebase project hash config 3. Copy what looks like a JSON "object" (don't include the `hash_config` string), and make it valid JSON: ```json theme={null} { "algorithm": "SCRYPT", "base64_signer_key": "...", "base64_salt_separator": "...", "rounds": 8, "mem_cost": 14 } ``` Save the file (we will refer to it as `hash-config.json` in the rest of the guide). ## Step 3. Convert Firebase users To convert your Firebase users, you can use either Docker or Go. In a directory containing the exported firebase user file and the hash config file, run: ```bash theme={null} docker run --rm \ -v "$(pwd):/data" \ ghcr.io/teamhanko/hanko:latest \ user convert firebase \ --input=/data/firebase-users.json \ --config=/data/hash-config.json \ --output=/data/hanko-import.json \ --dlq=/data/firebase-dlq.jsonl ``` ```bash theme={null} go run main.go user convert firebase \ --input="./firebase-users.json" \ --config="./hash-config.json" \ --output="./hanko-import.json" \ --dlq="./firebase-dlq.jsonl" ``` ## Step 4. Import users into Hanko Import the file (`hanko-import.json`) as described in [Import users](/guides/import_export/import-export-users#import-users). ## Caveats ### File size limits Firebase does not provide a fixed limit for the size of user export files, and export size depends on the number of users in the project. Hanko supports importing user files up to \~**50 MB** in size. If the converted import file exceeds this limit, it must be split into smaller chunks before importing. The conversion utility does not automatically split or paginate output files. ## Troubleshooting ### Conversion failures Failed conversions are written to a Dead Letter Queue (DLQ) file (default `firebase-dlq.jsonl`). Each line contains: * The error reason * The original Firebase user record ### Authentication fails after migration Check: 1. Correct Firebase hash config was used 2. User exists in `hanko-import.json` 3. User is not present in `firebase-dlq.jsonl` ## `firebase` command API ```bash theme={null} Convert user data exported via Firebase CLI to Hanko import data Usage: hanko user convert firebase [flags] Flags: --config string Firebase hash config file (JSON) --dlq string DLQ file containing user conversion errors (NDJSON) (default "firebase-dlq.jsonl") -h, --help help for firebase --input string Firebase export input file (JSON) --output string Hanko import output file (JSON) (default "hanko-import.json") --workers int Number of workers (default 12) ``` # Import and export users Source: https://docs.hanko.io/guides/import_export/import-export-users Learn how to import users from other platforms to Hanko, as well as how to export users from Hanko.
# Hanko User import and export guide **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to migrate user data to and from Hanko. You'll learn to import existing users from other authentication platforms and export user data for backup or migration purposes. **Key Technologies**: * JSON Data Formats * UUID Standards * Hanko Cloud Console * Hanko Admin API * Data Schema Validation * Bulk User Operations **Prerequisites**: * Active Hanko Cloud project * User data in proper JSON format * Understanding of UUID format requirements * Access to Hanko Cloud Console * Admin API access for exports **Tasks You'll Complete**: * Prepare user data in required JSON schema * Validate UUID format for user IDs * Import users through Hanko Cloud Console * Verify successful user migration * Export users using Admin API * Handle migration errors and edge cases
## Import users Migrating from another authentication provider? Import your existing users directly through the Hanko Cloud Console. All user IDs must be in UUID format for successful import. Navigate to [Hanko Cloud](https://cloud.hanko.io), select your project, and click 'Users' in the left sidebar. click import upload user file Structure your import file as a JSON array of user objects. Each object represents one user with their details. Reference the official [schema](https://raw.githubusercontent.com/teamhanko/hanko/refs/heads/main/backend/json_schema/hanko.user_import.json) for proper data formatting. ```json users.json theme={null} [ { "user_id": "d0f8fe0f-9fd0-4974-a927-63aaa54be787", "emails": [ { "address": "arvidwalsh@schumm.biz", "is_primary": true, "is_verified": true } ], "created_at": "2023-07-11T13:41:50.290862Z", "updated_at": "2023-07-11T13:41:50.290862Z" }, { "user_id": "c8d1628d-9258-4686-9063-1334fc7b0a7a", "emails": [ { "address": "horaciosteuber@emmerich.io", "is_primary": true, "is_verified": true } ], "created_at": "2023-07-11T13:41:50.290872Z", "updated_at": "2023-07-11T13:41:50.290872Z" } ] ``` ## Export users Export your user data using the [Hanko Admin API](https://docs.hanko.io/api-reference/admin/user-management/get-a-list-of-users) to retrieve comprehensive user information. A dedicated export feature matching the import functionality will be added to Hanko Cloud in the near future. The Hanko Admin API is available with paid plans. # Migration Guide Source: https://docs.hanko.io/guides/migrations/2.x.x-to-3.x.x Migration guide for upgrading from Hanko 2.x.x to 3.0.0 ## Overview Hanko 3.0.0 removes previously deprecated API endpoints. This guide outlines the breaking changes and migration path for upgrading from version 2.x.x to 3.0.0. Hanko 3.0.0 is scheduled for release on Hanko Cloud on **May 26, 2026**. Please plan your migration accordingly. ## Breaking Changes ### Deprecated API Endpoints The following Public API endpoints have been deprecated and will be removed in version 3.0.0: **Authentication Endpoints:** * [`POST /passcode/login/initialize`](/api-reference/public/passcode/initialize-passcode-login) * [`POST /passcode/login/finalize`](/api-reference/public/passcode/finalize-passcode-login) * [`POST /password/login`](/api-reference/public/password/do-password-login) * [`PUT /password`](/api-reference/public/password/createset-a-password) **WebAuthn Endpoints:** * [`POST /webauthn/login/initialize`](/api-reference/public/webauthn/initialize-webauthn-login) * [`POST /webauthn/login/finalize`](/api-reference/public/webauthn/finalize-webauthn-login) * [`POST /webauthn/registration/initialize`](/api-reference/public/webauthn/initialize-webauthn-registration) * [`POST /webauthn/registration/finalize`](/api-reference/public/webauthn/finalize-webauthn-registration) * [`GET /webauthn/credentials`](/api-reference/public/webauthn/get-a-list-of-webauthn-credentials) * [`DELETE /webauthn/credentials/{id}`](/api-reference/public/webauthn/deletes-a-webauthn-credential) * [`PATCH /webauthn/credentials/{id}`](/api-reference/public/webauthn/updates-a-webauthn-credential) **Configuration & Authentication:** * [`GET /.well-known/config`](/api-reference/public/well-known/get-public-hanko-configuration) * [`GET /thirdparty/auth`](/api-reference/public/third-party/initialize-third-party-login) * [`POST /token`](/api-reference/public/token/exchange-one-time-token-for-session) **User Management:** * [`POST /user`](/api-reference/public/user-management/get-user-details-by-email) * [`DELETE /user`](/api-reference/public/user-management/deletes-the-current-user) * [`POST /users`](/api-reference/public/user-management/create-a-user) * [`GET /users/{id}`](/api-reference/public/user-management/get-a-user-by-id) (use [GET `/me`](https://docs.hanko.io/api-reference/public/user-management/get-the-current-user-id) instead) **Email Management:** * [`GET /emails`](/api-reference/public/email-management/get-a-list-of-emails-of-the-current-user) * [`POST /emails`](/api-reference/public/email-management/add-a-new-email-address-to-the-current-user) * [`POST /emails/{id}/set_primary`](/api-reference/public/email-management/marks-the-email-address-as-primary-email) * [`DELETE /emails/{id}`](/api-reference/public/email-management/delete-an-email-address) **SAML:** * [`GET /saml/provider`](/api-reference/public/saml/get-a-saml-provider) ### Deprecated SDK functions * `getUser()` (use `getCurrentUser()` instead) ## Migration Path Exception: If your integration only uses `hanko-elements` version **1.0.0 or later** and does not use the Hanko API directly, you only need to check that you are using `getCurrentUser()` instead of `getUser()`. All deprecated endpoints have been replaced with the new **Flow API**, which provides a unified and streamlined authentication interface. Check out the [Understanding the Flow API guide](/using-the-api/understanding-the-flow-api) and [Build a custom login flow guide](/using-the-api/build-a-custom-login-page) for more information about building your own custom UI. ### Action Required To ensure a smooth transition: 1. Review your current implementation and check for any usage of deprecated API endpoints, SDK functions, or `hanko-elements` versions older than 1.0.0. 2. When using any of the deprecated endpoints, migrate to the Flow API before the v3.0.0 release date. Refer to the [Flow API documentation](/api-reference/flow) for implementation details. 3. When using `hanko-elements` versions older than 1.0.0, migrate to the latest version before the v3.0.0 release date. 4. Replace all usage of `getUser()` with `getCurrentUser()`. 5. Test your integration thoroughly in a development environment. Need assistance with your migration? Contact our [support team](https://www.hanko.io/support) or visit our [community Discord](/community-support) for help. # Sessions and tokens in Hanko Source: https://docs.hanko.io/guides/session-management Learn how to manage Hanko authentication sessions, configure duration, validate tokens, limit concurrent sessions, customize JWT tokens, and handle revocation.
**Hanko Session Management Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates session management in applications using Hanko for authentication. You'll learn to configure session lifetimes, implement session validation, handle multiple concurrent sessions, and customize session tokens with additional claims. **Key Technologies**: * JSON Web Tokens (JWT) * Session Cookies * JWT Signature Validation * Token Customization * Hanko Cloud Console **Prerequisites**: * Active Hanko project configured * Understanding of JWT concepts * Basic knowledge of authentication flows * Access to Hanko Cloud Console * Frontend/backend development knowledge **Tasks You'll Complete**: * Configure session duration and limits * Implement session validation logic * Set up session termination methods * Customize session tokens with claims * Handle concurrent session management * Configure cookie retention policies * Monitor and revoke active sessions
## Sessions and JSON Web Tokens Hanko creates a session when users authenticate (registration or sign-in). Each session is represented by a JSON Web Token ([JWT](https://datatracker.ietf.org/doc/html/rfc7519)) that encodes user claims as JSON objects. All Hanko JWTs are signed using JSON Web Signature ([JWS](https://datatracker.ietf.org/doc/html/rfc7515)) standards for security. Authentication operations (login, registration) return session tokens in the `X-Auth-Token` response header. When using [Hanko Elements](https://docs.hanko.io/guides/hanko-elements/introduction) or the [Hanko Frontend SDK](https://docs.hanko.io/resources/sdks#sdks), the session token is read from the `X-Auth-Token` header and used to set a cookie (name: `hanko`) on the client-side. If you use neither Hanko Elements nor the SDK, you have to take care of storing the session token yourself. Protected API requests must include the session token either in a `Cookie` header or as a `Bearer` token in the `Authorization` header (`Authorization: Bearer `). Upon session creation, a unique identifier is generated and stored in the database, linked to the corresponding user. This identifier is also included in the session JWT under the `session_id` claim. For subsequent requests, the API validates the JWT signature and uses the `session_id` to query the database for an active session match. This enables remote session revocation. As a result, if a user is logged in on one device but has multiple active sessions across other devices, the API’s [Profile](/api-reference/flow/profile) flow facilitates the listing and explicit termination of sessions on those devices. This functionality is also accessible through the UI via the Hanko Elements’ [Profile Component](/guides/hanko-elements/profile-component). ## Session validation Validate sessions manually using the `sessions/validate` [endpoint](/api-reference/public/session-management/validate-a-session-1). Send the session token in the request body for validation of expiry, signature, and session persistence. The validation response includes session validity status, token expiry information, and associated user claims. Alternatively, use the Hanko Frontend SDK for session validation. See [Using the Frontend SDK](/guides/hanko-elements/using-frontend-sdk#sessions) for implementation details. ### Authentication methods used When validating a session, the response includes the JWT `claims`. These claims contain an `amr` array (**Authentication Method References**) that allows you to determine how the current session was authenticated. * `amr` can contain multiple values (for example, a password login followed by a second factor). * Third-party logins are represented as `ext:`. The `amr` claim is also present in the JWT payload itself. See [JWT payload](#param-amr) for the list of supported `amr` values in both JWTs and session validation responses. ## Session termination Sessions can be terminated through various explicit and implicit methods, depending on your tenant configuration. ### Explicit user logout Users can manually log out through the `/logout` [endpoint](https://docs.hanko.io/api-reference/public/user-management/log-out-the-current-user). Successful logout requests clear session cookies and terminate the associated session. ### Limiting session duration Sessions automatically expire based on configured duration settings. The session duration controls how long users remain authenticated after login. Hanko Cloud defaults to 12 hours, but you can configure anywhere from 1 minute to 1 month. Configure session duration: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project 2. Navigate to `Settings > Session` 3. Set your desired `Session duration` and click `Save` ### Limiting idle session timeout You can configure sessions to expire after a period of inactivity by setting `idle_timeout`. When an idle timeout is configured, session validation responses include an `idle_expires_at` timestamp. This timestamp indicates when the session will expire if it is not used again before then. The session becomes invalid if it has exceeded the configured idle timeout. The `idle_expires_at` value is separate from the JWT `exp` claim: * `exp` defines the absolute lifetime of the session token. * `idle_expires_at` defines the inactivity-based expiration time. Only the `POST` session validation [endpoint](/api-reference/public/session-management/validate-a-session-1) renews the session's idle timeout. It updates the session's last-used timestamp and extends `idle_expires_at` accordingly. The `GET` session validation [endpoint](/api-reference/public/session-management/validate-a-session) does not renew the idle timeout. Configure session idle timeouts: 1. Log in to Hanko Cloud and select your project 2. Navigate to `Settings` > `Session` 3. Set your desired `Idle timeout` and click `Save`. ### Limiting concurrent sessions Sessions terminate automatically when exceeding the allowed concurrent session limit. Hanko defaults to 5 concurrent sessions - creating a new session invalidates the oldest existing session. Configure concurrent session limits: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project 2. Navigate to `Settings > Session` 3. Set your desired `Session limit` and click `Save` ### Limiting cookie retention period You can configure the retention period of session cookies. Possible configurations are: * **Persistent** (default): This type sets the `Max-Age` attribute of the cookie to the specified [session duration](#limiting-session-duration) (in seconds). The cookie will be automatically deleted from the browser once the specified expiry time has been reached. * **Session**: This type sets the `Max-Age` attribute of the cookie to 0, resulting in the cookie being deleted from the browser when the browser tab or window is closed. * **Prompt**: If you use [Hanko Elements](/guides/hanko-elements/introduction) (+1.3) then selecting this type results in Hanko Elements displaying a `Stay signed in` checkbox on the login form which allows users to determine the cookie retention period: if the checkbox is checked, the cookie will be a `Persistent` cookie, if it is unchecked the cookie will be a `Session` cookie. To configure the cookie retention period: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Session`. 3. Under `Stay signed in (cookie type)`, select the desired type and click `Save`. ## Session self-service There are a number of configurations options for your tenant that provide control over how users manage their session through the profile. ### Allowing session revocation You can configure whether the [Profile](https://docs.hanko.io/api-reference/flow/profile) flow permits session revocation via the dedicated `session_delete` action. If you are using [Hanko Elements](/guides/hanko-elements/introduction) version 1.3 or later, the Profile component provides interface elements that allow users to revoke active sessions, excluding the session currently in use. This session can be revoked manually through a [manual logout](#explicit-user-logout). To control self-service session revocation behaviour: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Session`. 3. Use the `Allow session revocation` toggle to allow or disallow end-user session revocation via profile. ### Showing sessions on profile You can control whether information about active sessions is returned in the `Profile` flow. If you use [Hanko Elements](/guides/hanko-elements/introduction) (+1.3) then information about active sessions is displayed in the [Profile component](guides/hanko-elements/profile-component). To control whether information about active sessions is returned from the `Profile` flow (and shown in Hanko Elements): 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Session`. 3. Use the `Show sessions on profile` toggle to include information about active sessions in the profil API response (and the [Hanko Elements profile component](guides/hanko-elements/profile-component)). ## Session metadata retention You can control whether active session metadata is persisted with a session and returned from session validation [endpoints](/api-reference/public/session-management/validate-a-session). This metadata currently includes the IP address and the user agent used to establish a session. To control the type of metadata retained with a session: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Session`. 3. You can configure the following options: * Use the `Acquire IP address` toggle to include information about the IP (IPv4/IPv6) address used to establish the session. * Use the `Acquire user agent` toggle to include information about the user agent used to establish the session. ## Session callbacks You can hook into the session lifecycle by using the Hanko Frontend SDKs central client. See [Using the Frontend SDK](/guides/hanko-elements/using-frontend-sdk#events) for details. ## Administrative session management The [Admin API](/api-reference/admin/introduction#learn-how-to-use-the-hanko-admin-api) allows administrators to [create sessions](/api-reference/admin/session-management/create-session), [list active sessions](/api-reference/admin/session-management/list-sessions) and [delete sessions](/api-reference/admin/session-management/delete-session) for a specific user. ## Session token customization Session tokens can be extended with custom claims by defining them using [Go's text/template syntax](https://pkg.go.dev/text/template). These claims are evaluated during JWT generation and may include static values, dynamic expressions, or nested structures. To define custom claims: 1. Log in to [Hanko Cloud](https://cloud.hanko.io) and select your project. 2. Navigate to `Settings > Session`. 3. Locate the `Customize session token` section. 4. Enter your custom claims in YAML format within the provided textarea. 5. Click `Save` to apply your changes. ### Accessing user data in templates Each template has access to user data via the `.User` field, which includes: * `.User.UserID`: The user's unique ID (string) * `.User.Email`: Email details (optional) * `.User.Email.Address`: The email address (string) * `.User.Email.IsPrimary`: Indicates if the email is the primary address (boolean) * `.User.Email.IsVerified`: Indicates if the email is verified (boolean) * `.User.FamilyName`: The user's family name (string, optional) * `.User.GivenName`: The user's given name (string, optional) * `.User.Name`: The user's full name (string, optional) * `.User.Picture`: The user's profile picture URL (string, optional) * `.User.Username`: The user's username (string, optional) * `.User.Metadata`: The user's public and unsafe metadata (optional) * `.User.Metadata.Public`: The user's public metadata (object) * `.User.Metadata.Unsafe`: The user's unsafe metadata (object) #### Accessing user metadata `.User.Metadata.Public` and `.User.Metadata.Unsafe` can be accessed and queried using [GJSON Path Syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) (try it out in the [playground](https://gjson.dev/)). Assume that a user's public metadata consisted of the following data: ```json theme={null} { "display_name": "GamerDude", "favorite_games": [ { "name": "Legends of Valor", "genre": "RPG", "playtime_hours": 142.3 }, { "name": "Space Raiders", "genre": "Sci-Fi Shooter", "playtime_hours": 87.6 } ] } ``` Then you could, for example, access this data in the following ways in your templates: ```yaml theme={null} display_name: '{{ .User.Metadata.Public "display_name" }}' favorite_games: '{{ .User.Metadata.Public "favorite_games" }}' favorite_games_with_playtime_over_100: '{{ .User.Metadata.Public "favorite_games.#(playtime_hours>100)" }}' favorite_genres: '{{ .User.Metadata.Public "favorite_games.#.genre" }}' ``` Ensure you use proper quoting when accessing metadata. `.User.Metadata.Public` and `.User.Metadata.Unsafe` are function calls internally and and the given path argument must be a string, so it must be double quoted. If you use use double quotes for your entire claim template then the path argument must be escaped, i.e.: `"{{ .User.Metadata.Public \"display_name\" }}"` ### Example configuration ```yaml theme={null} role: "user" # Static value user_email: "{{.User.Email.Address}}" # Templated string is_verified: "{{.User.Email.IsVerified}}" # Boolean from user data metadata: # Nested map greeting: "Hello {{.User.Username}}" source: '{{ .User.Metadata.Public "display_name" }}' # Data read from public metadata ui_theme: '{{ .User.Metadata.Unsafe "ui_theme" }}' # Data read from unsafe metadata scopes: # Slice with templated value - "read" - "write" - "{{if .User.Email.IsVerified}}admin{{else}}basic{{end}}" ``` ### Important notes and limitations * Custom claims are added at the top level of the session token [payload](#jwt-payload). * Claims with the following keys will be ignored because they are currently added to the JWT by default: * `sub` * `iat` * `exp` * `aud` * `iss` * `email` * `username` * `session_id` * Templates must conform to valid [Go text/template syntax](https://pkg.go.dev/text/template). Invalid templates are logged and excluded from the generated token. * Boolean strings ("true" or "false") from templates are automatically converted to actual booleans. ## Session JWT structure The session JWT is a [compact](https://datatracker.ietf.org/doc/html/rfc7515#section-3.1) JWS. It is a string composed of three base64 URL safe encoded parts ([header](#jwt-header), [payload](#jwt-payload) and signature), separated by a dot (`.`). The JWT payload contains the claims about a user. ### JWT Header ```json theme={null} { "alg": "RS256", "kid": "2288bfa9-3214-4f19-9757-92631190420b", "typ": "JWT" } ``` The algorithm used for signing this token. The key ID indicating which key was used to secure the token. The media type of this token. ### JWT Payload ```json theme={null} { "amr": [ "pwd", "totp" ], "aud": [ "example.com" ], "email": { "address": "user@example.com", "is_primary": true, "is_verified": true }, "exp": 17123108000, "iat": 1712307200, "session_id": "140f3967-ab87-4caa-80bd-603ac59c545f", "sub": "9930ac89-1584-488c-bd63-1607f03ab1e8", "username": "johndoe" } ``` Authentication Method References, JSON array of strings that are identifiers for authentication methods used in the authentication. Available options: * `pwd` => password * `passkey` => passkey * `otp` => email passcode * `ext:` => thirdparty provider, where `` is the internal provider ID, e.g. `ext:microsoft` * `totp` => 2FA authenticator app * `security_key` => 2FA security key Can contain multiple values. The order is generally, but not guaranteed, as follows: primary authentication methods (`pwd`, `passkey`, `otp`, `ext:`) first, then follow 2FA methods (`totp`, `security_key`). The audience for which the JWT was created. It specifies the intended recipient or system that should accept this JWT. When using Hanko Cloud, the `aud` will be your `App URL`. An object containing information about the user’s email address. The current primary email address of the user. A boolean field indicating whether the email address is the primary email. Currently, this field is redundant because only the primary email is included in the JWT. A boolean field indicating whether the email address has been verified. The (UNIX) timestamp indicating when the JWT will expire. The (UNIX) timestamp indicating when the JWT was created. The ID of the session. The ID of the user. The username of the user (if set). The payload further contains any [custom claims](#session-token-customization) that you have defined. # Sign in with Apple Source: https://docs.hanko.io/guides/social-sso/apple Step-by-step guide to integrating Sign in with Apple using Hanko. Enable secure authentication and seamless onboarding for your app's users.
**Hanko Apple OAuth Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Apple's "Sign in with Apple" OAuth service with Hanko, allowing users to authenticate using their Apple ID accounts. You'll learn to configure Apple's developer console, set up OAuth credentials, and implement Apple login in your application. **Key Technologies**: * OAuth 2.0 and OpenID Connect protocols * Apple Sign In OAuth provider * JWT (JSON Web Tokens) for secure authentication * Apple's private email relay service * ECDSA cryptographic signing for client secrets **Prerequisites**: * Active Hanko Cloud account with a configured project * Apple Developer account with appropriate permissions * Basic understanding of OAuth 2.0 flow * Docker installed for client secret generation **Tasks You'll Complete**: * Register and configure Apple App ID and Services ID * Generate required cryptographic keys and client secrets * Configure Apple OAuth credentials in Hanko Console * Implement Apple authentication in your frontend application * Handle Apple's private email relay service (optional)
1. Let's get the redirect url first from [Hanko Console](https://cloud.hanko.io/), as you'll need it in a moment. To do so, sign in to Hanko and select your project. Navigate to 'Settings' in the left sidebar and then to 'Identity Providers'. Copy the 'Redirect URL' from here. Hanko Callback URL ## Register App ID and Services ID * To get started you need an [Apple developer account](https://developer.apple.com/help/account/get-started/about-your-developer-account) and after you sign in, you'll need to [register an App ID](https://developer.apple.com/help/account/manage-identifiers/register-an-app-id). * In [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources), click 'Identifiers' in the sidebar, then click the add button (+) on the top left. * Select 'App IDs' from the list of options and click 'Continue'. Then 'Select App' as the type and click 'Continue'. * Provide your app information: App 'Description' and 'Bundle ID' (Apple recommends using a reverse-domain name style string i.e., `com.domainname.appname`). * In the 'Capabilities' tab below, check 'Sign in with Apple' and Click 'Continue', then review the registration information, then click 'Register'. * Now, you also need to register a 'Services ID'. Go to [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources), click 'Identifiers' in the sidebar, then click the add button (`+`) on the top. * Select `Services IDs` from the list of options and click 'Continue' and then provide your app information. * Click 'Continue', then 'Register'. ## Configure your Services ID * On [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources), click `Identifiers` in the sidebar, then select `Services IDs` from the dropdown menu on the right. * Select the `Services ID` you created in the previous step. * Enable `Sign In With Apple` for the `Services ID` by clicking the checkbox next to it. * Click `Configure`. * Select your [previously registered](#register-an-app-id) `App ID` as your `Primary App ID`. * In the shown modal, click the add button (`+`) next to `Website URLs`. * Add the *domain* of your [redirect URL](#redirect-url) to the `Domains and Subdomains` input (do not add a scheme, e.g. `https://`, or path information). * In the `Return URLs` input, enter the complete [redirect URL](#redirect-url) of your app which you found in the previous step. * Click `Next` at the bottom right. * Click `Done` at the bottom to close the modal. * Back on the `Edit your Services ID Configuration` view, click `Continue` at the top right, then click `Save`. ## Create key and download key file Next, you need to create a `Key` and download a `Key` file. You need this file to generate your client secret in the [next step](#generate-secret). * On [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources), click `Keys` in the sidebar, then click the add button (`+`) next to the `Keys` heading. * Enter a `Key Name`. * In the options table below the `Key Name` input, check `Sign in with Apple`. * In the same table row, click `Configure` to the right. * In the `Configure Key` view, select your [previously registered](#register-an-app-id) `App ID` in the`Primary App ID` dropdown. * Click `Save` on the top right. * Back on the `Register a New Key` view, click `Continue`, then click `Register` on the top right. * On the `Download Your Key` view, click `Download` on the top right to save the key file. * Click `Done` on the top right. ## Generate a client secret Sign in with Apple requires a client secret to authorize API requests. The secret must be a JSON Web Token (JWT) signed with the Elliptic Curve Digital Signature Algorithm (ECDSA) with the P-256 curve and the SHA-256 hash algorithm. To make secret generation as easy as possible, we provide a script that can be executed using [Docker](https://docker.com). If you do not have Docker installed, see the [official installation instructions](https://docs.docker.com/get-docker/). The script requires the following information: * `private_key`: This is the path to the key file you downloaded in the [previous step](#create-key-and-download-key-file). Per default the key file name should look like this: `AuthKey_XXXXXXXXXX.p8`. Because we use Docker in this case, we will use the path to the key file on your filesystem to mount the file into the Docker container (we'll get to this, see the command below). * `team_id`: This is the Team ID your Apple Developer account is associated with. * See [Locate your Team ID](https://developer.apple.com/help/account/manage-your-team/locate-your-team-id/#:~:text=In%20the%20top%20navigation%20of,to%20view%20your%20Team%20ID.) in the official Apple documentation. * `services_id`: This is `Services ID` you created in the [Register a Services ID](#register-a-services-id) step. You can always review this ID in the Apple Developer console: * On [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources), click `Identifiers` in the sidebar, then select `Services IDs` from the dropdown menu on the right. * Find the relevant entry in the list (the required value is the value in the `Identifier` column). * `key_id`: This is the ID of the private key from the [previous step](#create-key-and-download-key-file). The `XXXXXXXXXX` part of the default `AuthKey_XXXXXXXXXX.p8` filename is the key ID. You can also review this ID in the Apple Developer console: * On [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources), click `Keys` in the sidebar, then select `Services IDs`. * Select your key in the list. * The ID can be found under `View Key Details` > `Key ID` As previously mentioned, we will mount the `private_key` to the container by mapping the path on your filesystem to a path on the container filesystem, e.g. `~/Downloads/AuthKey_XXXXXXXXXX.p8:/tmp/AuthKey_XXXXXXXXXX.p8`. From the command line, run (replace `<...>` placeholders with your data): ```shell theme={null} docker run -v : ghcr.io/teamhanko/hanko siwa \ --private_key \ --team_id \ --services_id \ --key_id > client_secret.txt ``` The command will save the client secret in a file `client_secret.txt`. Secrets expire after 6 months and must be regenerated before the expiration. 1. Head back to Identity providers in Hanko and under 'Identity provider settings' configure the following: Hanko Callback URL * **Error Redirect URL**: This URL, on your frontend, is where the Hanko API redirects if an error occurs during third-party sign-in. With hanko-elements web components, it should link to the page embedding the web component to process errors correctly. * **Allowed Redirect URL**: A URL on your frontend that the Hanko API can redirect to after a successful third-party authentication. Using hanko-elements web components? Make it the URL of the embedding page. Supports wildcard matching through globbing: * `https://*.example.com` matches `https://foo.example.com` and `https://bar.example.com`. * `https://foo.example.com/*` matches URLs like `https://foo.example.com/page1` and `https://foo.example.com/page2`. * Use \*\* to act as a super-wildcard/match-all. 2. In the 'Providers' section, select Apple and enable its toggle switch. 3. Input the earlier noted 'Services ID' and 'Secret Key', then click 'Save'. Hanko Callback URL Whether you choose to use the pre-designed UI from the `@teamhanko/hanko-elements` package or opt for a custom UI with the `@teamhanko/hanko-frontend-sdk` will determine your approach to frontend integration. 1. Integrate the `` component from `hanko-elements` based on our frontend guides. If everything is configured correctly, the component will display a button for signing in with Apple in the login view. Make sure to configure the page the web component is embedded on as your error redirect URL as well as an allowed redirect URL. After successful Apple authentication, the backend sets a session cookie and any authentication errors are displayed within the component. 1. For a custom UI, initialize third party sign-in using `@teamhanko/hanko-frontend-sdk`. 2. Create a Hanko client instance and call `thirdParty.auth` with `apple` as the provider. ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko(""); async function signInWithApple() { try { await hanko.thirdParty.auth("apple", ""); } catch (error) { // handle error } } ``` 3. On successful authentication, the API redirects you to the given redirect URL. The URL query includes a one time token that must be exchanged for a JWT. Use the `token.validate` method on your client to validate the token: ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko(""); async function onLoad() { try { await hanko.token.validate(); } catch (error) { // handle error } // you should now have a JWT cookie set } ``` On success, the API issues a JWT which is then set by the SDK as a cookie (hanko). All other SDK methods can now use the cookie to make authenticated requests to the API. ## On using Apple's private email relay service Sign in with Apple gives allows users to [hide their original email address](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js/communicating_using_the_private_email_relay_service#overview) when authorizing your app during the authentication flow and instead use an anonymous, automatically generated email address. Emails are then routed through Apples private relay email service. In order to [send email messages through the relay service](https://developer.apple.com/help/account/configure-app-capabilities/configure-private-email-relay-service) to the users' personal inboxes (Hanko sends out passcodes for email verification and account recovery), you'll need to register your outbound email domains. All registered domains must create Sender Policy Framework (SPF) DNS TXT records in order to transit Apple's private mail relay. If a user signs up using `Sign in with Apple` and chooses to hide their real email address, then the private relay address will become the primary email for the user. Should a user then choose to sign in with an email address (and not via `Sign in with Apple`), then the private relay email address must be used, *not* the real email address associated with her Apple account. ### Register domains with Apple * On [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources), click `Services` in the left sidebar. * In the `Sign in with Apple for Email Communication` panel, click `Configure`. * Next to the `Email Sources` heading, click the add (`+`) button. * In the `Register your email sources` modal, enter your `Domains and Subdomains` and/or specific `Email Addresses`. * If you use Hanko Cloud and do *not* want to use a custom SMTP server, enter `hanko.io` in the `Domains and Subdomains` input. You do not need to provide an SPF DNS record by yourself. * If you use Hanko Cloud and *do* want to use a [custom SMTP server](?environment=cloud#configure-smtp), enter your custom domain in the `Domains and Subdomains` input. Remember to provide an SPF DNS record for your domain in order to pass Apple's SPF check. * Click `Next`, then click `Register`. * Your domains should be listed in the `Email Sources` table. Emails are only relayed if the SPF check (see the `Status` column) was successful. ### Configure SMTP with Hanko If you use Hanko Cloud and are on a paid subscription tier you can configure your own SMTP server. * Sign in to [cloud.hanko.io](https://cloud.hanko.io). * Select your `Organization`. * Select your `Project`. * In the left sidebar, click `Settings`, then select `SMTP`. * Enter your SMTP credentials and sender data. * The domain of your `Sender email address` should be registered as an email source in the Apple developer console to allow communication through Apple's private relay service (see the [previous step](#register-domains)). * Click `Save`. # Sign in with Discord Source: https://docs.hanko.io/guides/social-sso/discord Step-by-step guide to integrating Sign in with Discord using Hanko. Enable secure authentication and seamless onboarding for your app's users.
**Hanko Discord OAuth Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Discord OAuth authentication with Hanko, allowing users to sign in using their Discord accounts. You'll learn to set up a Discord application, configure OAuth credentials, and implement Discord login in your application. **Key Technologies**: * OAuth 2.0 authentication protocol * Discord OAuth provider and API * JWT (JSON Web Tokens) for secure session management * RESTful API integration * Frontend SDK integration **Prerequisites**: * Active Hanko Cloud account with a configured project * Discord account for developer access * Basic understanding of OAuth 2.0 authentication flow * Frontend application ready for integration **Tasks You'll Complete**: * Create and configure a Discord application in the developer portal * Set up OAuth redirect URLs and obtain client credentials * Configure Discord OAuth settings in Hanko Console * Implement Discord authentication in your frontend application * Handle authentication success and error states
## Prerequisites Before starting this integration, ensure you have: 1. A Hanko Cloud account and project. [Set up your account here](https://docs.hanko.io/setup-hanko-cloud) if you haven't already. 2. A Discord account for accessing the developer portal. [Create an account here](https://discord.com/register) if needed. ## Get your provider redirect URL You'll need to configure a redirect URL in your Discord application. This URL determines where Discord redirects users after successful authentication. The redirect URL combines your Hanko API base URL with the [`/thirdparty/callback`](http://docs.hanko.io/api/public#tag/Third-Party/operation/thirdPartyCallback) endpoint. To find your redirect URL: 1. Sign in to [cloud.hanko.io](https://cloud.hanko.io). 2. Select your `Organization`. 3. Select your `Project`. 4. In the left sidebar, click `Settings`, then select `Identity providers`. 5. Find your redirect URL in the `Redirect URL` input. Hanko Callback URL You need the redirect URL for [creating a new Discord application](#create-a-new-discord-application) in the next step and when [configuring your credentials in Hanko](#configure-discord-credentials-in-hanko) (you will also configure the remaining configuration options visible in the above screen in this step). ## Create a Discord application 1. Navigate to the [Discord developer portal](https://discord.com/developers/applications). 2. On the main dashboard, select `Applications` in the left sidebar. 3. On the top right, select `New Application`. Create a new application 4. Enter a name for your application, accept the Discord Terms of Service, and click `Create`. New application registration modal 5. On your application dashboard, select `OAuth2` in the left sidebar. 6. In the `Redirects` panel, click `Add Redirect`. Add redirect URL 7. Enter the `Redirect URL` you obtained in the [previous step](#get-your-provider-redirect-url) in the input that appears. 8. Click `Save changes`. Enter redirect URL ## Get your client ID and secret 1. In the `OAuth2` settings of your application, copy the `Client ID`. 2. Click `Reset Secret`, follow the prompts to generate a new secret, then copy the generated secret. Copy application credentials ## Configure Discord credentials in Hanko 1. In the Hanko Cloud Console, navigate to your project `Settings` and select `Identity providers`. 2. Configure these redirect URLs: Hanko Callback URL * **Error Redirect URL**: The frontend URL where Hanko redirects users if authentication fails. For applications using `hanko-elements` web components, this should be the page containing the component to handle errors properly. * **Allowed Redirect URL**: The frontend URL where Hanko redirects users after successful authentication. For `hanko-elements` applications, this should be the page containing the authentication component. The allowed redirect URL supports wildcard matching through globbing: * `https://*.example.com` matches `https://foo.example.com` and `https://bar.example.com`. * `https://foo.example.com/*` matches URLs like `https://foo.example.com/page1` and `https://foo.example.com/page2`. * Use \*\* to act as a super-wildcard/match-all. 3. In the `Providers` section, select `Discord` and enable it using the toggle switch. 4. Enter the `Client ID` and `Client Secret` you obtained from the Discord developer console. 5. Click `Save` to apply your configuration. ## Implement Discord login in your frontend You can integrate Discord authentication using either: * Pre-built UI components from [`@teamhanko/hanko-elements`](https://www.npmjs.com/package/@teamhanko/hanko-elements) * Custom implementation with [`@teamhanko/hanko-frontend-sdk`](https://www.npmjs.com/package/@teamhanko/hanko-frontend-sdk) Follow our [quickstart guides](https://docs.hanko.io/quickstarts) to integrate the `` component from `@teamhanko/hanko-elements` into your application. Once configured, the component will automatically display a Discord sign-in button in the login interface. Make sure to configure the page the web component is embedded on as your `error redirect URL` as well as an `allowed redirect URL` (see the [previous step](#configure-discord-credentials-in-hanko)). After successful Discord authentication, Hanko issues a session cookie and the component continues its normal flow. Authentication errors are automatically captured and displayed within the component. For custom UI implementations, use the `@teamhanko/hanko-frontend-sdk` to handle Discord authentication. Create a [`Hanko` client](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/Client.html) instance and call the `thirdParty.auth` method with `discord` as the provider. ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; // you can find the Hanko API URL on the dashboard of your project // in the Hanko Cloud Console const hanko = new Hanko(""); async function signInWithDiscord() { try { // the redirect url argument must be one of the allowed redirect URLs // configured in the previous step. await hanko.thirdParty.auth("discord", ""); } catch (error) { // handle error } } ``` After successful authentication, the API redirects to your specified URL with a one-time token in the query parameters. Exchange this token for a JWT using the `token.validate` method: ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; // you can find the Hanko API URL on the dashboard of your project // in the Hanko Cloud Console const hanko = new Hanko(""); async function onLoad() { try { await hanko.token.validate(); } catch (error) { // handle error } // you should now have a JWT cookie set } ``` On successful validation, the SDK sets a JWT cookie (hanko) that enables authenticated API requests for all other SDK methods. # Sign in with Facebook Source: https://docs.hanko.io/guides/social-sso/facebook Step-by-step guide to integrating Sign in with Facebook using Hanko. Enable secure authentication and seamless onboarding for your app's users.
**Hanko Facebook OAuth Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Facebook Login OAuth authentication with Hanko, enabling users to sign in using their Facebook accounts. You'll learn to create a Facebook app, configure OAuth settings, and implement Facebook authentication in your application. **Key Technologies**: * OAuth 2.0 authentication protocol * Facebook Login API and Graph API * JWT (JSON Web Tokens) for secure session management * Facebook App Review process * RESTful API integration **Prerequisites**: * Active Hanko Cloud account with a configured project * Facebook developer account and access to Facebook Developer Portal * Basic understanding of OAuth 2.0 authentication flow * Frontend application ready for integration **Tasks You'll Complete**: * Create and configure a Facebook application in the developer portal * Set up Facebook Login with required permissions and redirect URLs * Configure Facebook OAuth credentials in Hanko Console * Implement Facebook authentication in your frontend application * Understand Facebook app publishing requirements
## Prerequisites Before starting this integration, ensure you have: 1. A Hanko Cloud account and project. [Set up your account here](https://docs.hanko.io/setup-hanko-cloud) if you haven't already. 2. A Facebook developer account. Visit the [Facebook developer portal](https://developers.facebook.com/) and select `Login` to create an account. ## Get your provider redirect URL You'll need to configure a redirect URL in your Facebook application. This URL determines where Facebook redirects users after successful authentication. The redirect URL combines your Hanko API base URL with the [`/thirdparty/callback`](/api-reference/public/third-party/third-party-provider-callback) endpoint. To find your redirect URL: 1. Sign in to [cloud.hanko.io](https://cloud.hanko.io). 2. Select your `Organization`. 3. Select your `Project`. 4. In the left sidebar, click `Settings`, then select `Social connections`. 5. Find your redirect URL in the `Redirect URL` input. Hanko Redirect URL You need the redirect URL for [creating a new Facebook application](#create-a-new-facebook-application) in the next step. ## Create a Facebook application 1. Navigate to and log in to the [Facebook developer portal](https://developers.facebook.com). 2. In the top navigation, select `Apps`. 3. Click `Create app` in the center of the page or on the top right. Facebook apps dashboard 4. Enter your app details and click `Next`. Facebook app details prompt on app creation 5. On the `Use cases` view, select `Authenticate and request data from users with Facebook Login`. 6. Click `Next`. Facebook use cases prompt on app creation 7. On the `Business` view, select `I don't want to connect a business portfolio yet` (or connect your existing business portfolio if available). 8. Click `Next`. Facebook business portfolio connection prompt on app creation 9. On the `Create app` view, click `Go to dashboard`. Facebook finalize app creation 10. On the app dashboard, click `Customize adding a Facebook Login button` in the `Add and customize use cases` section. Facebook customize login use case 11. In the `Customize use case` view, select `Permissions` in the left sidebar. 12. Click the `add` button for the `email` permission in the permissions table to enable email access. Facebook customize login use case permissions by adding the email permission 13. In the `Customize use case` view, select `Settings` in the left sidebar. 14. Under `Valid OAuth Redirect URIs`, add the redirect URL you [retrieved from the Hanko Console](#get-your-provider-redirect-url). Facebook customize login use case settings by adding valid OAuth redirect URLs When testing locally, you don't need to add localhost redirect URLs as Facebook automatically allows all `http://localhost` redirects. ## Get your client ID and secret 1. Navigate to the `App settings` > `Basic` for your app. 2. Copy the `App ID`. 3. `Show` and copy the `App Secret`. Facebook customize login use case settings by adding valid OAuth redirect URLs ## Configure Facebook credentials in Hanko 1. In the Hanko Cloud Console, navigate to your project `Settings` and select `URLs`. 2. Configure a **Default Redirect URL** - the frontend URL where Hanko redirects users if authentication fails. For applications using `hanko-elements` web components, this should be the page containing the component to handle errors properly. 3. Configure your **Allowed Redirect URL**s - the frontend URLs where Hanko can redirect users after successful authentication. For `hanko-elements` applications, this should be the page containing the authentication component. The allowed redirect URL supports wildcard matching through globbing: * `https://*.example.com` matches `https://foo.example.com` and `https://bar.example.com`. * `https://foo.example.com/*` matches URLs like `https://foo.example.com/page1` and `https://foo.example.com/page2`. * Use \*\* to act as a super-wildcard/match-all. Hanko Redirect URLs configuration 4. Navigate to your project `Settings` and select `Social connections`. 5. In the `Providers` section, find `Facebook` and expand its configuration. 6. Enable the Facebook provider using the toggle switch. 7. Enter the Facebook `App ID` as the `Client ID`. 8. Enter the Facebook `App Secret` as the `Client Secret`. 9. Click `Save` to apply your configuration. Configure Facebook provider in Hanko Cloud social connection settings ## Implement Facebook login in your frontend You can integrate Facebook authentication using either: * Pre-built UI components from [`@teamhanko/hanko-elements`](https://www.npmjs.com/package/@teamhanko/hanko-elements) * Custom implementation with [`@teamhanko/hanko-frontend-sdk`](https://www.npmjs.com/package/@teamhanko/hanko-frontend-sdk) Follow our [quickstart guides](https://docs.hanko.io/quickstarts) to integrate the `` component from `@teamhanko/hanko-elements` into your application. Once configured, the component will automatically display a Facebook sign-in button in the login interface. Make sure to configure the page the web component is embedded on as your `error redirect URL` as well as an `allowed redirect URL` (see the [previous step](#configure-facebook-credentials-in-hanko)). After successful Facebook authentication, Hanko issues a session cookie and the component continues its normal flow. Authentication errors are automatically captured and displayed within the component. For custom UI implementations, use the `@teamhanko/hanko-frontend-sdk` to handle Facebook authentication. Create a [`Hanko` client](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/Client.html) instance and call the `thirdParty.auth` method with `facebook` as the provider. ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; // you can find the Hanko API URL on the dashboard of your project // in the Hanko Cloud Console const hanko = new Hanko(""); async function signInWithFacebook() { try { // the redirect url argument must be one of the allowed redirect URLs // configured in the previous step. await hanko.thirdParty.auth("facebook", ""); } catch (error) { // handle error } } ``` After successful authentication, the API redirects to your specified URL with a one-time token in the query parameters. Exchange this token for a JWT using the `token.validate` method: ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko(""); async function onLoad() { try { await hanko.token.validate(); } catch (error) { // handle error } // you should now have a JWT cookie set } ``` On successful validation, the SDK sets a JWT cookie (hanko) that enables authenticated API requests for all other SDK methods. ## Publish your app After following this guide, your Facebook app will have an `Unpublished` status, which limits its usage to developers and testers. To allow all users to authenticate with Facebook, you must submit your app for Facebook's [App Review](https://developers.facebook.com/docs/resp-plat-initiatives/individual-processes/app-review) process and get it approved for public use. # Sign in with GitHub Source: https://docs.hanko.io/guides/social-sso/github Step-by-step guide to integrating Sign in with GitHub using Hanko. Enable secure authentication and seamless onboarding for your app's users.
**Hanko GitHub OAuth Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate GitHub OAuth authentication with Hanko, allowing users to sign in using their GitHub accounts. You'll learn to create a GitHub OAuth app, configure authentication settings, and implement GitHub login in your application. **Key Technologies**: * OAuth 2.0 authentication protocol * GitHub OAuth Apps and API * JWT (JSON Web Tokens) for secure session management * RESTful API integration * Frontend SDK integration **Prerequisites**: * Active Hanko Cloud account with a configured project * GitHub account for developer access * Basic understanding of OAuth 2.0 authentication flow * Frontend application ready for integration **Tasks You'll Complete**: * Create and configure a GitHub OAuth application * Set up redirect URLs and obtain client credentials * Configure GitHub OAuth credentials in Hanko Console * Implement GitHub authentication in your frontend application * Handle authentication success and error states
* First, obtain the redirect URL from [Hanko Console](https://cloud.hanko.io/), as you'll need it for GitHub configuration. Sign in to Hanko and select your project. Navigate to 'Settings' in the left sidebar and then to 'Identity Providers'. Copy the 'Redirect URL' from here. Hanko Callback URL * Navigate to GitHub and click on your profile photo at the top right corner. * Select 'Settings' at the bottom of the sidebar menu. GitHub settings option * Scroll down and select 'Developer Settings' in the left sidebar. GitHub developer settings * Choose 'OAuth Apps' followed by 'New OAuth App'. This opens the registration form for creating your OAuth application. GitHub New OAuth app option The redirect URL is crucial. It guides GitHub on where to redirect users post-authentication. It's a blend of Hanko API's base URL and the /thirdparty/callback endpoint. The exact Hanko API base URL (and hence your redirect URL) hinges on your Hanko setup: whether you use Hanko Cloud or have a self-hosted Hanko API. * Return to the OAuth app registration form, fill in the required details, and paste the copied redirect URL into the 'Application Callback URL' field. Complete the registration by clicking 'Register application'. GitHub OAuth registration form * You'll now see an overview of your OAuth app. Note down the provided 'Client ID'. Generate a 'Client Secret' by selecting 'Generate a new client secret'. Copy both values, as you'll need them in the next step. GitHub OAuth registration form * Return to Identity providers in Hanko and under 'Identity provider settings' configure the following: Hanko Callback URL * **Error Redirect URL**: This URL, on your frontend, is where the Hanko API redirects if an error occurs during third-party sign-in. With hanko-elements web components, it should link to the page embedding the web component to process errors correctly. * **Allowed Redirect URL**: A URL on your frontend that the Hanko API can redirect to after a successful third-party authentication. Using hanko-elements web components? Make it the URL of the embedding page. Supports wildcard matching through globbing: * `https://*.example.com` matches `https://foo.example.com` and `https://bar.example.com`. * `https://foo.example.com/*` matches URLs like `https://foo.example.com/page1` and `https://foo.example.com/page2`. * Use \*\* to act as a super-wildcard/match-all. * In the 'Providers' section, select GitHub and enable its toggle switch. * Input the earlier noted 'Client ID' and 'Client Secret', then click 'Save'. Hanko Callback URL Whether you choose to use the pre-designed UI from the `@teamhanko/hanko-elements` package or opt for a custom UI with the `@teamhanko/hanko-frontend-sdk` will determine your approach to frontend integration. * Integrate the `` component from `hanko-elements` based on our frontend guides. If everything is good, the component will display a button for signing in with 'Github' in login view. Make sure to configure the page the web component is embedded on as your error redirect URL as well as an allowed redirect URL. Post successful GitHub authentication, the backend sets a session cookie and errors during authentication are displayed within the component accordingly. * For a custom UI, initialize third party sign-in using `@teamhanko/hanko-frontend-sdk`. * Create Hanko client instance and call `thirdParty.auth` with github as the provider. ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko(""); async function signInWithGitHub() { try { await hanko.thirdParty.auth("github", ""); } catch (error) { // handle error } } ``` * On successful authentication, the API redirects you to the given redirect URL. The URL query includes a one time token that must be exchanged for a JWT. Use the `token.validate` method on your client to validate the token: ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko(""); async function onLoad() { try { await hanko.token.validate(); } catch (error) { // handle error } // you should now have a JWT cookie set } ``` On success, the API issues a JWT which is then set by the SDK as a cookie (hanko). All other SDK methods can now use the cookie to make authenticated requests to the API. # Sign in with Google Source: https://docs.hanko.io/guides/social-sso/google Step-by-step guide to integrating Sign in with Google using Hanko. Enable secure authentication and seamless onboarding for your app's users.
**Hanko Google OAuth Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Google OAuth authentication with Hanko, allowing users to sign in using their Google accounts. You'll learn to set up a Google Cloud Console project, configure OAuth consent, and implement Google login in your application. **Key Technologies**: * OAuth 2.0 and OpenID Connect protocols * Google Cloud Console and Google Auth Platform * JWT (JSON Web Tokens) for secure session management * Google OAuth 2.0 authorization server * RESTful API integration **Prerequisites**: * Active Hanko Cloud account with a configured project * Google account for Cloud Console access * Basic understanding of OAuth 2.0 authentication flow * Frontend application ready for integration **Tasks You'll Complete**: * Create a Google Cloud Console project and configure OAuth consent * Set up OAuth 2.0 credentials and redirect URLs * Configure Google OAuth settings in Hanko Console * Implement Google authentication in your frontend application * Handle authentication success and error states
* First, obtain the redirect URL from the [Hanko Console](https://cloud.hanko.io/), as you'll need this for Google configuration. Sign in to the Hanko console and select your project. Navigate to 'Settings' in the left sidebar and then to 'Social connections'. Copy the 'Redirect URL'. Hanko Callback URL * Verify that your allowed redirect URL is configured correctly for your application. Navigate to the 'URLs' tab in the left sidebar. Ensure that Allowed redirect URLs includes your App URL + '\*\*'. Hanko allowed redirect url * Navigate to [Google Cloud Console](https://console.cloud.google.com/), sign in and click on 'Select a project' at the top left. Google settings option * Select 'New Project' from the top right of modal. Google settings option * Provide a 'Project name', if you want the project to be part of an organization, assign it using the 'Location' input and hit 'Create' Google settings option * Type 'OAuth' in the search bar and choose 'OAuth consent screen' from the results. Google settings option * Configure your Google Auth Platform by clicking 'Get started' to begin setup. Google auth configuration * Name your app and select a user support Email. Google App Information * Select 'User Type' depending on your requirements Google Project Audience * Navigate to 'Google Auth Platform' > 'Audience' and publish your app. Google test users * Click 'Clients' in the left sidebar, then click 'Create client'. Create oauth client * Select 'Web application' as the application type. Google settings option * Choose a name and paste the Redirect URL (that you obtained from the Hanko console) as an 'Authorized redirect URI'. Google auth client setup * The Google console will display information about the OAuth client. Copy and save both the 'Client ID' and 'Client secret', as you'll need these in the next step. Google settings option * In the 'Social connections' section, select Google and enable its toggle switch. * Input the earlier noted 'Client ID' and 'Client Secret', then click 'Save'. Hanko Callback URL Whether you choose to use the pre-designed UI from the `@teamhanko/hanko-elements` package or opt for a custom UI with the `@teamhanko/hanko-frontend-sdk` will determine your approach to frontend integration. * Integrate the `` component from `hanko-elements` based on our frontend guides. If everything is good, the component will display a button for signing in with 'Google' in login view. Make sure to configure the page the web component is embedded on as your error redirect URL as well as an allowed redirect URL. Post successful Google authentication, the backend sets a session cookie and errors during authentication are displayed within the component accordingly. * For a custom UI, initialize third party sign-in using `@teamhanko/hanko-frontend-sdk`. * Create Hanko client instance and call `thirdParty.auth` with google as the provider. ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko(""); async function signInWithGoogle() { try { await hanko.thirdParty.auth("google", ""); } catch (error) { // handle error } } ``` * On successful authentication, the API redirects you to the given redirect URL. The URL query includes a one time token that must be exchanged for a JWT. Use the `token.validate` method on your client to validate the token: ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko(""); async function onLoad() { try { await hanko.token.validate(); } catch (error) { // handle error } // you should now have a JWT cookie set } ``` On success, the API issues a JWT which is then set by the SDK as a cookie (hanko). All other SDK methods can now use the cookie to make authenticated requests to the API. # Sign in with LinkedIn Source: https://docs.hanko.io/guides/social-sso/linkedin Step-by-step guide to integrating Sign in with LinkedIn using Hanko. Enable secure authentication and seamless onboarding for your app's users.
**Hanko LinkedIn OAuth Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate LinkedIn OAuth authentication with Hanko, enabling users to sign in using their LinkedIn professional accounts. You'll learn to create a LinkedIn application, configure Sign In with LinkedIn using OpenID Connect, and implement LinkedIn authentication in your application. **Key Technologies**: * OAuth 2.0 and OpenID Connect protocols * LinkedIn Sign In with OpenID Connect * JWT (JSON Web Tokens) for secure session management * LinkedIn Developer Portal and API * RESTful API integration **Prerequisites**: * Active Hanko Cloud account with a configured project * LinkedIn account for developer portal access * Basic understanding of OAuth 2.0 authentication flow * LinkedIn company page (required for app creation) **Tasks You'll Complete**: * Create and configure a LinkedIn application with Sign In capabilities * Request access to Sign In with LinkedIn using OpenID Connect * Configure OAuth redirect URLs and obtain client credentials * Configure LinkedIn OAuth credentials in Hanko Console * Implement LinkedIn authentication in your frontend application
## Prerequisites 1. You need a Hanko Cloud account and a project. Learn more on how to set them up [here](https://docs.hanko.io/setup-hanko-cloud). 2. You need a LinkedIn account. You can create an account [here](https://www.linkedin.com/signup). ## Get your provider redirect URL When creating an LinkedIn application, you need to provide a redirect URL that determines where the third party provider redirects after a successful login. This redirect URL consists of the base URL of the Hanko API and the [`/thirdparty/callback`](http://docs.hanko.io/api/public#tag/Third-Party/operation/thirdPartyCallback) endpoint. You can always view your redirect URL in the Hanko Cloud Console: 1. Sign in to [cloud.hanko.io](https://cloud.hanko.io). 2. Select your `Organization`. 3. Select your `Project`. 4. In the left sidebar, click `Settings`, then select `Social connections`. 5. Find your redirect URL in the `Redirect URL` input. Hanko Callback URL You need the redirect URL for [creating a new LinkedIn application](#create-a-new-linkedin-application) in the next step and [configuring your credentials with Hanko](#configure-credentials-with-hanko) (you will also configure the remaining configuration options visible in the above screen in this step). ## Create a new LinkedIn application 1. Navigate to and log in to the [LinkedIn developer portal](https://www.linkedin.com/developers/login). dashboard 2. Click on the `Create app` button. create linkedin app 3. Enter your application name in `App name`. 4. Enter your LinkedIn company page url in `LinkedIn Page` or create one. 5. (Optional) Enter your privacy policy page url in `Privacy policy URL`. 6. Upload a logo for your application. 7. Accept the terms and conditions. 8. Click on the `Create app` button. product list 9. Search for the `Sign In with LinkedIn using OpenID Connect` card from the product list. 10. Click `Request access`. request access for sign in 11. Accept the terms and conditions. 12. Click on the `Request access` Button. 13. The card should now show as added product. 14. Click on the `Auth` tab up top and scroll to `OAuth 2.0 settings` OAuth 2.0 settings 15. Click on the `pencil` next to `Authorized redirect URLs for your app` 16. Click on `+ Add redirect URL` 17. Enter the `Redirect URL` you obtained in the [first step](#get-your-provider-redirect-url) as the value. 18. Click on the `Update` button. ## Get your client ID and secret You can view the client ID as well as the secret of your app in the `Auth` tab on your app page. You will need this when [configuring your credentials with Hanko](#configure-credentials-with-hanko) Client ID and Secret ## Configure credentials with Hanko 1. In the Hanko Cloud Console, navigate to your project `Settings` and select `Social connections`. 2. Configure the following: Hanko Callback URL * **Error Redirect URL**: This is the URL target in your frontend the Hanko API redirects to if an error occurs during third party sign-in. If your frontend [uses the `hanko-elements` web components](#frontend-integration), this URL should be the URL of the page that embeds the web component such that errors can be processed properly by the web component. * **Allowed Redirect URL**: This is the URL target in your frontend the Hanko API is allowed to redirect to after third party authentication was successful. If your frontend [uses the `hanko-elements` web components](#frontend-integration), this URL should be the URL of the page that embeds the web component. The allowed redirect URL supports wildcard matching through globbing: * `https://*.example.com` matches `https://foo.example.com` and `https://bar.example.com`. * `https://foo.example.com/*` matches URLs like `https://foo.example.com/page1` and `https://foo.example.com/page2`. * Use \*\* to act as a super-wildcard/match-all. 2. In the `Providers` section, select `LinkedIn` and use the `Enable provider` toggle to enable the provider. 3. Provide the `Client ID` and `Client Secret` you obtained in one of the [previous section](#get-your-client-id-and-secret) in the remaining inputs. 4. Click `Save`. ## Frontend integration To enable a login with LinkedIn in your frontend application we recommend using either our pre-built UI as provided by the [`@teamhanko/hanko-elements`](https://www.npmjs.com/package/@teamhanko/hanko-elements) package or building a custom UI using the [`@teamhanko/hanko-frontend-sdk`](https://www.npmjs.com/package/@teamhanko/hanko-frontend-sdk). We recommend following one of our [quickstart guides](https://docs.hanko.io/quickstarts) to integrate the `` component from our `@teamhanko/hanko-elements` package in your frontend application . On successful integration, the component will display a button for signing in with `LinkedIn` in the login view of the component. Make sure to configure the page the web component is embedded on as your `error redirect URL` as well as an `allowed redirect URL` (see the [previous step](#configure-credentials-with-hanko)). On successful authentication with the provider, the backend issues a session cookie and the web component continues the usual component flow on success. Errors that occur during third party provider authentication are also picked up and displayed in the web component accordingly. When building your own UI, you can use the `@teamhanko/hanko-frontend-sdk` to initialize third party sign in. Create a [`Hanko` client](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/Client.html) instance and call the `thirdParty.auth` method with `linkedin` as your provider and the target URL in your app you want to redirect to after authentication. ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; // you can find the Hanko API URL on the dashboard of your project // in the Hanko Cloud Console const hanko = new Hanko(""); async function signInWithLinkedIn() { try { // the redirect url argument must be one of the allowed redirect URLs // configured in the previous step. await hanko.thirdParty.auth("linkedin", ""); } catch (error) { // handle error } } ``` On successful authentication, the API redirects you to the given redirect URL. The URL query includes a one time token that must be exchanged for a JWT. Use the `token.validate` method on your client to validate the token: ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko(""); async function onLoad() { try { await hanko.token.validate(); } catch (error) { // handle error } // you should now have a JWT cookie set } ``` On success, the API issues a JWT which is then set by the SDK as a cookie (hanko). All other SDK methods can now use the cookie to make authenticated requests to the API. # Sign in with Microsoft Source: https://docs.hanko.io/guides/social-sso/microsoft Step-by-step guide to integrating Sign in with Microsoft using Hanko. Enable secure authentication and seamless onboarding for your app's users.
**Hanko Microsoft OAuth Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Microsoft OAuth authentication with Hanko, allowing users to sign in using their Microsoft accounts (including personal, work, or school accounts). You'll learn to create an Azure application registration, configure Microsoft Entra ID, and implement Microsoft authentication in your application. **Key Technologies**: * OAuth 2.0 and OpenID Connect protocols * Microsoft Entra ID (formerly Azure Active Directory) * Azure Application Registration * JWT (JSON Web Tokens) for secure session management * Microsoft Graph API integration **Prerequisites**: * Active Hanko Cloud account with a configured project * Microsoft Azure account for application registration * Basic understanding of OAuth 2.0 authentication flow * Understanding of Azure multi-tenant applications **Tasks You'll Complete**: * Create and configure an Azure application registration * Set up multi-tenant authentication with proper account type selection * Generate client secrets and configure redirect URLs * Configure optional claims for enhanced security (UPN, email verification) * Configure Microsoft OAuth credentials in Hanko Console * Implement Microsoft authentication in your frontend application
## Prerequisites 1. You need a Hanko Cloud account and a project. Learn more on how to set them up [here](https://docs.hanko.io/setup-hanko-cloud). 2. You need a Microsoft Azure account. You can create account [here](https://azure.microsoft.com/en-us/free/). ## Get your provider redirect URL When creating an Azure Application, you need to provide a redirect URL that determines where the third party provider redirects after a successful login. This redirect URL consists of the base URL of the Hanko API and the [`/thirdparty/callback`](http://docs.hanko.io/api/public#tag/Third-Party/operation/thirdPartyCallback) endpoint. You can always view your redirect URL in the Hanko Cloud Console: 1. Sign in to [cloud.hanko.io](https://cloud.hanko.io). 2. Select your `Organization`. 3. Select your `Project`. 4. In the left sidebar, click `Settings`, then select `Identity providers`. 5. Find your redirect URL in the `Redirect URL` input. Hanko Callback URL You need the redirect URL for [creating a new Azure application](#create-a-new-azure-application) in the next step and when [configuring your credentials with Hanko](#configure-credentials-with-hanko) (you will also configure the remaining configuration options visible in the above screen in this step). ## Create a new Azure application 1. Navigate to and sign in to the [Azure portal](https://portal.azure.com). 2. Click the hamburger menu in the navbar in the top left. 3. Select `Microsoft Entra ID`. Access Microsoft Entra ID 4. Select `App registrations` in the left sidebar. Access app registrations 5. On the top left, click on `New registration`. Request new app registration 6. Enter your Application name. 7. Under `Supported account types` choose the third option: `Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)`. The above option allows any user to login to your application. Other account types (single-tenant only, multi-tenant or public only) are currently not supported. 8. Under the `Redirect URI` section select `Web` as the platform. 9. Enter the `Redirect URL` you obtained in the [first step](#get-your-provider-redirect-url) as the value. 10. Click on `Register`. Fill app registration form ## Get your client ID and secret Next, you need to obtain your client ID and client secret. 1. You can view the client ID of your app in the `Essentials` section on the `Overview` page (`Application (client) ID`) of your application/app registration. You will need this when [configuring your credentials with Hanko](#configure-credentials-with-hanko) View client ID 2. To create a client secret, select `Certificates & Secrets` in the sidebar. View app certificates and secrets 3. Select the `Client secrets` tab. Hanko currently does not support using `Certificates`. 4. Select `New client secret`. Request new client secret 5. Give your secret a name. 6. Select an expiration date. Hanko Cloud currently does not provide any means to auto-rotate secrets, so keep the expiration date of your secret in mind and manually refresh the secret when necessary. 7. Click `Add` to create the secret. Configure new client secret 8. After creating the secret, make sure to copy the secret `Value`. You will need this when [configuring your credentials with Hanko](#configure-credentials-with-hanko). You can no longer copy the `Value` of the secret after a full page refresh. If you you forget to do so, simply create another secret and remove the old one. ## Token configuration Next, we recommend making some additional adjustments to the claims containend in the tokens handed out by Microsoft. ### Add UPN claim It is possible that users do not have a primary email address set but Hanko requires email addresses to create accounts. To ensure Hanko is provided with an email address, set the optional `upn` ([UserPrincipalName](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/plan-connect-userprincipalname#upn-format)) claim. In general, the `upn` domain suffix cannot be changed to an unverified domain and hence the `upn` will be prioritized over a users' `email` (see the [next section](#protection-against-the-noauth-vulnerbility)). To configure the claim: 1. Select your app registration and then select the `Token configuration` section. View app token configuration 2. Select `Add optional claim`. Add new optional token claim 3. Select `ID` as the token type. 4. Tick the `upn` checkbox to select it as an additional optional claim. 5. Click `Add`. Configure optional claim 6. Tick the checkbox to set the required Microsoft Graph permissions. 7. Click `Add`. Set Microsoft Graph permissions for the upn claim ### Protection against the nOAuth vulnerability In 2023 Descope [discovered](https://www.descope.com/blog/post/noauth) a vulnerability resulting from misconfigurations of multi-tenant apps that could potentially lead to account takeovers when linking accounts with the provider (automatic account linking is not activated by default in Hanko, but may be preferable in many situations). To mitigate this vulnerability Microsoft provides the following guidance: 1. Configure the `authenticationBehaviors` setting of your application to disallow unverified email domains. This should be the default case for newly created applications, so no further steps should be required. If your application was created before the publication of the vulnerability, and the application previously used unverified emails, you might need to manually alter the `authenticationBehaviours` as described [here](https://learn.microsoft.com/en-us/entra/identity-platform/migrate-off-email-claim-authorization#how-do-i-protect-my-application-immediately). 2. Use the optional `xms_edov` token claim to check if an email domain owner has been verified. We recommend implementing this additional security measure in case the tokens do not contain a `upn` (e.g. if the claim has not been configured or the configuration has been reverted) and decisions have to be based on a users' `email` property. To do so, first open your applications `Manifest`. View app manifest 3. Find the `optionalClaims.idToken` key in the manifest. It should already contain an entry for the `upn` claim you configured in the [previous step](#add-upn-claim). Add an entry for the `xms_edov` claim to the array (make a backup of the manifest file, just in case): ```json theme={null} "optionalClaims": { "idToken": [ { "name": "upn", "source": null, "essential": false, "additionalProperties": [] }, { "name": "xms_edov", "source": null, "essential": false, "additionalProperties": [] } ] } ``` You may notice that after adding the `xms_edov` claim, it is listed in the `Token configuration` section but it is marked with a warning icon claiming that *"\[t]his claim is not supported and will not be returned in the token"*. At the time of writing this does not appear to be correct and the claim is in fact returned in the ID token. 4. Add another optional claim, only this time add the `email` claim. Proceed just as described in the [previous section](#add-upn-claim) when you added the `upn` claim. Hanko per default requires email verification. When you configure the `xms_edov` claim, Hanko will reject any attempt at connecting a Microsoft account if no verified email address is provided. ## Configure credentials with Hanko 1. In the Hanko Cloud Console, navigate to your project `Settings` and select `Identity providers`. 2. Configure the following: Hanko Callback URL * **Error Redirect URL**: This is the URL target in your frontend the Hanko API redirects to if an error occurs during third party sign-in. If your frontend [uses the `hanko-elements` web components](#frontend-integration), this URL should be the URL of the page that embeds the web component such that errors can be processed properly by the web component. * **Allowed Redirect URL**: This is the URL target in your frontend the Hanko API is allowed to redirect to after third party authentication was successful. If your frontend [uses the `hanko-elements` web components](#frontend-integration), this URL should be the URL of the page that embeds the web component. The allowed redirect URL supports wildcard matching through globbing: * `https://*.example.com` matches `https://foo.example.com` and `https://bar.example.com`. * `https://foo.example.com/*` matches URLs like `https://foo.example.com/page1` and `https://foo.example.com/page2`. * Use \*\* to act as a super-wildcard/match-all. 2. In the `Providers` section, select `Microsoft` and use the `Enable provider` toggle to enable the provider. 3. Provide the `Client ID` and `Client Secret` you obtained in one of the [previous section](#get-your-client-id-and-secret) in the remaining inputs. 4. Click `Save`. ## Frontend integration To enable a login with Microsoft in your frontend application we recommend using either our pre-built UI as provided by the [`@teamhanko/hanko-elements`](https://www.npmjs.com/package/@teamhanko/hanko-elements) package or building a custom UI using the [`@teamhanko/hanko-frontend-sdk`](https://www.npmjs.com/package/@teamhanko/hanko-frontend-sdk). We recommend following one of our [quickstart guides](https://docs.hanko.io/quickstarts) to integrate the `` component from our `@teamhanko/hanko-elements` package in your frontend application . On successful integration, the component will display a button for signing in with `Microsoft` in the login view of the component. Make sure to configure the page the web component is embedded on as your `error redirect URL` as well as an `allowed redirect URL` (see the [previous step](#configure-credentials-with-hanko)). On successful authentication with the provider, the backend issues a session cookie and the web component continues the usual component flow on success. Errors that occur during third party provider authentication are also picked up and displayed in the web component accordingly. When building your own UI, you can use the `@teamhanko/hanko-frontend-sdk` to initialize third party sign in. Create a [`Hanko` client](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/Client.html) instance and call the `thirdParty.auth` method with `microsoft` as your provider and the target URL in your app you want to redirect to after authentication. ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; // you can find the Hanko API URL on the dashboard of your project // in the Hanko Cloud Console const hanko = new Hanko(""); async function signInWithMicrosoft() { try { // the redirect url argument must be one of the allowed redirect URLs // configured in the previous step. await hanko.thirdParty.auth("microsoft", ""); } catch (error) { // handle error } } ``` On successful authentication, the API redirects you to the given redirect URL. The URL query includes a one time token that must be exchanged for a JWT. Use the `token.validate` method on your client to validate the token: ```js theme={null} import { Hanko } from "@teamhanko/hanko-frontend-sdk"; const hanko = new Hanko(""); async function onLoad() { try { await hanko.token.validate(); } catch (error) { // handle error } // you should now have a JWT cookie set } ``` On success, the API issues a JWT which is then set by the SDK as a cookie (hanko). All other SDK methods can now use the cookie to make authenticated requests to the API. # Access user data from your backend Source: https://docs.hanko.io/guides/user-data/backend Learn how to access Hanko user data in your backend code.
**Hanko User Data Retrieval Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to retrieve user data from Hanko in backend environments, including validating sessions, extracting information from JWTs, and using the Admin API. **Key Technologies**: * JWT (JSON Web Tokens) * Hanko Admin API **Prerequisites**: * Active Hanko project with configured API URL * Basic understanding of JavaScript/TypeScript * Admin API access (for Admin API features - Pro/Enterprise plans only) **Tasks You'll Complete**: * Validate user sessions and extract JWT claims * Fetch comprehensive user data using the Hanko Admin API * Implement proper authentication checks in your application
## Get user data from the session cookie The [`/sessions/validate`](/api-reference/public/session-management/validate-a-session-1) endpoint allows you to extract user claims from the JWT token. ```js theme={null} // Checks the validity of the current session and returns the user claims const validateSession = async (sessionToken) => { const apiUrl = process.env.HANKO_API; const options = { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ session_token: sessionToken }), }; const response = await fetch(`${apiUrl}/sessions/validate`, options); return response.json(); }; const sessionToken = ""; // Get the session token, this depends on your framework you use. const sessionStatus = await validateSession(sessionToken); console.log("user data:", sessionStatus); // Example output: // { // is_valid: true, // claims: { // subject: "123e4567-e89b-12d3-a456-426614174000", // session_id: "789abc", // expiration: "2025-04-25T12:00:00Z", // email: { address: "user@example.com", is_primary: true, is_verified: true }, // custom_field: "value" // } // } ``` You can refer to the [User Metadata guide](/guides/user-data/user-metadata) for details on managing user metadata included in the JWT payload. For information on customizing session tokens with metadata, see the [Session Token Customization guide](/guides/session-management#session-token-customization). ## Get user data using the Hanko Admin API The [Hanko Admin API](/api-reference/admin) provides comprehensive access to user status, management capabilities, metrics, and more. This example focuses on retrieving data for a specific user. To fetch data for a specific user, make a request to the [`/users/{id}`](https://docs.hanko.io/api-reference/admin/user-management/get-a-user-by-id) endpoint of the Hanko Admin API, where `id` is the user ID obtained from the JWT. The Hanko Admin API is available in Hanko Pro and Enterprise plans. Check out our [pricing page](https://hanko.io/pricing) for more information. You also need an API key secret to access the Hanko Admin API which can be generated under the `Settings > API Keys` section of your project. ```js theme={null} const getUserData = async () => { const adminAPI = process.env.ADMIN_API; const adminSecret = process.env.ADMIN_SECRET; const options = { method: "GET", headers: { Authorization: `Bearer ${adminSecret}`, }, }; const response = await fetch(`${adminAPI}/users/${userID}`, options); return response.json(); }; const userData = await getUserData(); console.log("user data:", userData); ``` # Access user data from your frontend Source: https://docs.hanko.io/guides/user-data/frontend Learn how to access Hanko user data in your frontend code.
**Hanko User Data Retrieval Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to retrieve user data from Hanko in frontend environments, including accessing user profiles, validating sessions, extracting information from JWTs. **Key Technologies**: * Hanko Frontend SDK * Hanko Elements * JWT (JSON Web Tokens) **Prerequisites**: * Active Hanko project with configured API URL * Basic understanding of JavaScript/TypeScript **Tasks You'll Complete**: * Retrieve current user profile data using the Frontend SDK * Validate user sessions and extract JWT claims * Implement proper authentication checks in your application
## Get user data from API To access user data in your frontend application, use the `hanko.getCurrentUser()` method from the [hanko-frontend-sdk](https://www.npmjs.com/package/@teamhanko/hanko-frontend-sdk) (also available via [hanko-elements](https://www.npmjs.com/package/@teamhanko/hanko-elements)). ```js theme={null} import { Hanko } from "@teamhanko/hanko-elements"; const hankoApi = ""; const hanko = new Hanko(hankoApi); // Fetches the current user's profile information const user = await hanko.getCurrentUser(); console.log("User profile:", user); // Example output: // { // user_id: "123e4567-e89b-12d3-a456-426614174000", // emails: [{ address: "user@example.com", is_primary: true, is_verified: true }], // username: { id: "f2882293-3c39-451d-a7cb-4cf3375e0c66", username: "johndoe" }, // created_at: "2025-01-01T10:00:00Z", // updated_at: "2025-04-01T12:00:00Z" // } ``` ## Get user data from the session cookie To extract user claims from the JWT token, use the `hanko.validateSession()` function. ```js theme={null} import { Hanko } from "@teamhanko/hanko-elements"; const hankoApi = ""; const hanko = new Hanko(hankoApi); // Checks the validity of the current session and returns the user claims const sessionStatus = await hanko.validateSession(); console.log("Session status:", sessionStatus); // Example output: // { // is_valid: true, // claims: { // subject: "123e4567-e89b-12d3-a456-426614174000", // session_id: "789abc", // expiration: "2025-04-25T12:00:00Z", // email: { address: "user@example.com", is_primary: true, is_verified: true }, // custom_field: "value" // } // } ``` # User metadata Source: https://docs.hanko.io/guides/user-data/user-metadata Store custom JSON data on user profiles with private, public, or unsafe visibility. Learn how to manage it via APIs and include it in session JWTs.
**Hanko User Metadata Management Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide explains how to work with Hanko's user metadata system, including the three metadata types (private, public, unsafe), their access permissions, character limitations, and how to read and modify metadata through various APIs. **Key Technologies**: * Hanko Public API * Hanko Admin API * JWT Templates and Session Customization * User Profile Management * JSON Data Storage **Prerequisites**: * Active Hanko project * Understanding of API authentication * Admin API access (for private and public metadata management) * Basic knowledge of JSON data structures **Tasks You'll Complete**: * Understand the three metadata types and their access levels * Learn character limits and JSON storage requirements * Access metadata through Public and Admin APIs * Modify metadata using appropriate endpoints * Implement metadata in JWT templates for session customization * Choose the right metadata type for your use case
Hanko supports arbitrary user metadata storage. Metadata is organized into three distinct types, each with different access and modification permissions: | Metadata type | Public API | Admin API | | ------------- | ---------------------------- | --------------------- | | Private | No read or write access | Read and write access | | Public | Read access | Read and write access | | Unsafe | Read access and write access | Read and write access | Each metadata type supports a maximum of 3,000 characters. Metadata is stored as compact JSON (whitespace is ignored). JSON syntax characters (`{`, `:`, `"`, `}`) count toward the character limit. Multibyte UTF-8 characters (like emojis or non-Latin characters) count as 1 character each. ## Private metadata Use private metadata for sensitive information that must remain hidden from client applications (e.g., internal flags/IDs, configuration settings, or access control details). ### Accessing private metadata Private metadata is accessible exclusively through the Admin API using the [Get metadata of a user](/api-reference/admin/user-metadata-management/get-metadata-of-a-user) endpoint. ### Setting private metadata Private metadata can only be created and modified through the Admin API using the [Patch metadata of a user](/api-reference/admin/user-metadata-management/patch-metadata-of-a-user) endpoint. ## Public metadata Use public metadata for non-sensitive information that should be readable but not modifiable by client applications (e.g., user roles, UI preferences, display settings). ### Accessing public metadata Public metadata is accessible through the Public API, Admin API, and JWT templates for session customization: * `Public API`: * Public metadata is returned in the `user` object in the payload on the `success` state in a [Login](/api-reference/flow/login) and [Registration](/api-reference/flow/registration) flow as well as in the payload on the `profile_init` state in a [Profile](/api-reference/flow/profile) flow. * Public metadata is returned as part of the response of the [Get a user by ID](/api-reference/public/user-management/get-a-user-by-id) endpoint. * `Admin API`: * Public metadata is returned as part of the response of the [Get metadata of a user](/api-reference/admin/user-metadata-management/get-metadata-of-a-user) endpoint. * Public metadata is returned as part of the response of the [Get a user by ID](/api-reference/admin/user-management/get-a-user-by-id) endpoint. * `JWT Templates`: * Public metadata can be accessed through the `User` context object available on session JWT customization. See [Session token customization](/guides/session-management#session-token-customization) for more details. ### Setting public metadata Public metadata can only be created and modified through the Admin API using the [Patch metadata of a user](/api-reference/admin/user-metadata-management/patch-metadata-of-a-user) endpoint. ## Unsafe metadata Use unsafe metadata for non-sensitive, temporary, or experimental data that doesn't require strict safety guarantees. ### Accessing unsafe metadata Unsafe metadata is accessible through the Public API, Admin API, and JWT templates for session customization: * `Public API`: * Unsafe metadata is returned in the `user` object in the payload on the `success` state in a `Login` and `Registration` flow as well as in the payload on the `profile_init` state in a `Profile` flow. * Unsafe metadata is returned as part of the response of the [Get a user by ID](/api-reference/public/user-management/get-a-user-by-id) endpoint. * `Admin API`: * Unsafe metadata is returned as part of the response of the [Get metadata of a user](/api-reference/admin/user-metadata-management/get-metadata-of-a-user) endpoint. * Unsafe metadata is returned as part of the response of the [Get a user by ID](/api-reference/admin/user-management/get-a-user-by-id) endpoint. * `JWT Templates`: * Unsafe metadata can be accessed through the `User` context object available on session JWT customization. See [Session token customization](/guides/session-management#session-token-customization) for more details. ### Setting unsafe metadata Unsafe metadata can be created and modified through both the Public API and Admin API: * `Public API`: * Unsafe metadata can be set using the `patch_metadata` action in the [Profile](/api-reference/flow/profile) flow. * `Admin API`: * Unsafe metadata can be set using the [Patch metadata of a user](/api-reference/admin/user-metadata-management/patch-metadata-of-a-user) endpoint. # Using Hanko webhooks Source: https://docs.hanko.io/guides/webhooks Discover how to implement Hanko webhooks to receive real-time authentication event notifications. Learn to create, manage, and respond to user-related triggers.
**Hanko Webhooks Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to implement webhooks with Hanko to receive real-time notifications about authentication events. You'll learn to create webhook endpoints, validate payloads, and process user lifecycle and email events for data synchronization and custom workflows. **Key Technologies**: * HTTP Webhooks * JSON Web Tokens (JWT) * Webhook Signature Verification * Event Processing * RESTful APIs * Hanko Cloud Console **Prerequisites**: * Hanko Pro or Enterprise plan subscription * Public HTTPS endpoint for webhook delivery * Understanding of HTTP request handling * JWT verification knowledge * Server-side development capabilities **Tasks You'll Complete**: * Create webhook subscriptions in Hanko Cloud * Build webhook endpoint for event processing * Validate JWT signatures for security * Parse and process different event types * Handle user lifecycle events (create, update, delete) * Process email send events for custom delivery * Implement error handling and retry logic
This feature is only available in the Pro or Enterprise [plans](https://www.hanko.io/pricing). ## About webhooks Webhooks enable real-time event subscriptions within your Hanko project, automatically delivering event data to your server whenever authentication events occur. This facilitates user data synchronization and custom workflow automation. Create webhooks by specifying a callback URL and selecting events to monitor. When subscribed events occur, Hanko sends HTTP POST requests with event data to your specified endpoint. Your application can then process this data through a publicly accessible HTTPS endpoint. ```mermaid theme={null} sequenceDiagram participant A as Relying Party participant B as Hanko A->>B: Create webhook B->>B: Event occurs B->>A: HTTP POST to callback URL A->>A: Parse webhook payload A->>A: Validate event data A->>A: Process event data A-->>B: Acknowledge delivery ``` ## Creating webhooks Set up webhooks through these steps: Log in to [Hanko Cloud Console](https://cloud.hanko.io), select your organization and project, then navigate to `Settings > Webhooks`. Click `Create webhook`, enter your callback URL, and select events for subscription. Review [Events](#events) for complete event type information. You can implement either a single webhook endpoint handling multiple events or separate webhooks for specific event types, depending on your architecture preferences. ## Handling webhook deliveries Process webhook deliveries through these steps: Implement a publicly accessible HTTP POST endpoint at your configured callback URL to receive webhook deliveries. Extract the webhook [event payload](#event-payload) containing event information and JWT-encoded event data. Verify JWT signatures using your tenant's [.well-known](/api-reference/public/well-known/get-json-web-key-set) endpoint to ensure deliveries originate from Hanko and remain uncompromised. Parse the JWT to extract event data from the token payload. Event data structures vary by event type - see [Event types and token payloads](#event-types-and-token-payloads). Handle the extracted event data according to your application's specific requirements. This example uses [express](https://www.npmjs.com/package/express) and the [jose](https://www.npmjs.com/package/jose) package to parse and verify JWTs. ```shell theme={null} npm install express jose ``` The example assumes usage of a single HTTP endpoint for all event types but you could just as well configure multiple webhooks and use multiple HTTP endpoints. ```javascript theme={null} // These are the dependencies you should have installed for // this example. const express = require('express'); const { createRemoteJWKSet, jwtVerify } = require('jose'); const app = express(); // Middleware for parsing requests with a JSON payload. app.use(express.json()); // Step 1: This defines a POST endpoint at the `/webhook` path. // This path should match the path portion of the URL that you // specified for the callback URL when you created the webhook. // Once you edit a webhook by updating the callback URL of your // webhook, you should change this to match the path portion of // the updated URL for your webhook. app.post('/webhook', async (req, res) => { // Step 2: Extract the event and token from the request body. // You could use the event type to branch and apply // logic/code for specific event types. // This example assumes one endpoint for all event types so // extracting the `event` property may lead to an unused // variable. const { event, token } = req.body; try { // This would likely come from your environment/config. // You can always find your tenant ID on the dashboard // for your project in the Hanko Cloud Console. const tenantId = 'your-tenant-id'; // See also the API reference: // http://docs.hanko.io/api-reference/public/well-known/get-json-web-key-set const jwksUrl = `https://${tenantId}.hanko.io/.well-known/jwks.json`; // Step 3 + 4: Fetch the JWKS of your Hanko tenant, verify // the token signature using the JWKS and extract the // payload. const jwks = createRemoteJWKSet(new URL(jwksUrl)); const { payload } = await jwtVerify(token, jwks); console.log('Decoded token payload:', payload); // Step 6: Do further processing according to your // application's needs. } catch (error) { console.error('Error processing the token:', error.message); } // Your endpoint should respond with a 2XX response within 30 seconds // of receiving a webhook delivery to indicate that the delivery was // successfully received. If your server takes longer than that to // respond, then Hanko terminates the connection and considers the // delivery a failure. res.sendStatus(202); }); // Start the Express server const PORT = 3000; app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); }); ``` Your server **must** return the complete certificate chain otherwise the request will fail. ## Editing and removing webhooks Manage existing webhooks through these steps: Log in to [Hanko Cloud](https://cloud.hanko.io), select your organization and project, then navigate to `Settings > Webhooks`. Find your webhook and click the three dots (`...`). Choose `Edit` to modify the callback URL or event subscriptions, or `Delete` to remove the webhook completely. ## Events Hanko offers various event types for subscription. Each event type determines the structure and content of the payload delivered to your callback URL. ### Event payload The structure of the event payload is the same across all event types. It contains the event type and the event data in the form of a JSON Web Token (JWT). ```json user.create theme={null} { "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6...", "event": "user.create" } ``` The JWT that contains the actual webhook event data. It is a JSON Web Signature (JWS). Webhook recipients should verify the signature to ensure that the webhook deliveries were sent by Hanko and have not been tampered with. The event that triggered this webhook ### Event types and token payloads Events are structured hierarchically with some events subsuming the occurrence of multiple ("sub")-events. These types of events do not actually appear as the value for the `event` property in the webhook event payload. Subscribing to these types of events when creating a webhook is a convenient way to group certain event types and allows you to structure your callback endpoints around these groups. A webhook's event data is encoded as a JWT in the webhook's callback request body. You need to parse the token to access the token's payload which contains the actual event data (see [Handling webhook deliveries](#handling-webhook-deliveries) for an example). #### user Subscribing to this event implies subscription to the following events: [`user.create`](#user-create), [`user.delete`](#user-delete), [`user.login`](#user-login), [`user.udpate.email.create`](#user-update-email-create), [`user.update.email.delete`](#user-update-email-delete), [`user.update.email.primary`](#user-update-email-primary), [`user.update.password.update`](#user-update-password-update) [`user.update.username.create`](#user-update-username-create), [`user.update.username.delete`](#user-update-username-delete), [`user.update.username.update`](#user-update-username-update) #### user.create This event is triggered when a new user is created. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### user.delete This event is triggered when a user is deleted. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### user.login This event is triggered when a user logs in. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### user.update Subscribing to this event implies subscription to the following events: [`user.udpate.email.create`](#user-update-email-create), [`user.update.email.delete`](#user-update-email-delete), [`user.update.email.primary`](#user-update-email-primary), [`user.update.password.update`](#user-update-password-update) [`user.update.username.create`](#user-update-username-create), [`user.update.username.delete`](#user-update-username-delete), [`user.update.username.update`](#user-update-username-update) #### user.update.email Subscribing to this event implies subscription to the following events: [`user.udpate.email.create`](#user-update-email-create), [`user.update.email.delete`](#user-update-email-delete), [`user.update.email.primary`](#user-update-email-primary) #### user.update.email.create This event is triggered when an email is created for a user. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### user.update.email.delete This event is triggered when a user's email is deleted. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### user.update.email.primary This event is triggered when a user's email is set as the primary email. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### user.update.password.update This event is triggered when a user updates their password through the profile. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### user.update.username Subscribing to this event implies subscription to the following events: [`user.update.username.create`](#user-update-username-create), [`user.update.username.delete`](#user-update-username-delete), [`user.update.username.update`](#user-update-username-update) #### user.update.username.create This event is triggered when a username is created for a user. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### user.update.username.delete This event is triggered when a user's username is deleted. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### user.update.username.update This event is triggered when a user's username is updated. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "created_at": "2025-01-15T12:57:56.724052Z", "emails": [ { "id": "d31be36d-08d7-409f-8437-1920628e6e51", "address": "test@example.com", "is_verified": true, "is_primary": true, "created_at": "2025-01-15T13:57:56.72784Z", "updated_at": "2025-01-15T13:57:56.72801Z" } ], "id": "42fbd0dc-28fb-4144-892c-c2c4a0f8f5d8", "identities": [ { "id": "b3af92c5-414c-4c6b-a3ea-82ee263badef", "provider_id": "123456abcd", "provider_name": "testprovider", "email_id": "d31be36d-08d7-409f-8437-1920628e6e51", "created_at": "2025-01-17T13:40:11Z", "updated_at": "2025-01-17T13:40:13Z" } ], "ip_address": "127.0.0.1", "otp": { "id": "a7efd1ee-d7b2-440e-9284-625e06931745", "created_at": "2025-01-17T13:39:29.081428Z" }, "password": { "id": "6ec87b0c-67db-42ef-9adb-d106734bde02", "created_at": "2025-01-15T13:57:56.735651Z", "updated_at": "2025-01-15T13:57:56.735651Z" }, "updated_at": "2025-01-15T13:57:56.724255Z", "username": { "id": "61580d7d-0c11-4c25-bfca-ace21a14cc01", "username": "testmakker", "created_at": "2025-01-15T14:45:00.293001Z", "updated_at": "2025-01-17T13:46:41.700373Z" }, "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "webauthn_credentials": [ { "id": "eaYxbrFQJjl5dW5SAr0KznEmHwAen8HUAiaKN9ijsDY", "public_key": "pQECAyYgASFYIMq-SVnCDGIJjK2TAJyEQyXNtOw7x_MuEVUQuW80-AOcIlggyEcR_v5C8PuhrThwgx2urmRqviIb7dyXmGr3oyWk2rU", "attestation_type": "packed", "aaguid": "70a4ab68-d027-451a-9c86-3b8fd8414f68", "last_used_at": "2025-01-17T12:38:28.698563Z", "created_at": "2025-01-17T12:38:28.698563Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": true }, { "id": "BPtYkS1prrGu1owU3StJwWM5uYtVoD1-h4N_rPHrB84", "public_key": "pQECAyYgASFYILo4i3yC0V2kciBHL96EOx08h32CXXIFnuUmggHOhkGvIlggQFIp4CeJhzGpCiTNuQQoyiKV7oMLYxM549ctLJXJkZ0", "attestation_type": "packed", "aaguid": "649b9062-5892-4223-832b-921c5bce5827", "last_used_at": "2025-01-17T12:39:06.718171Z", "created_at": "2025-01-17T12:39:06.718171Z", "transports": [ "usb" ], "backup_eligible": false, "backup_state": false, "mfa_only": false } ] }, "evt": "", // the corresponding event type "exp": 1737118303, "iat": 1737118003, "sub": "hanko webhooks" } ``` The recipients the token is intended for The ID of the user Time of creation of the user The ID of the email The actual email address Time of creation of the email Indicates whether this is the primary email Indicates whether this email is verified Time of last update of the email The ID of the identity The ID of the user at the third party provider The name of the third party provider The ID of the email the identity is related to Time of creation of the identity Time of last update of the identity MFA OTP credential of the user ID of the OTP credential Time of creation of the OTP credential Representation of the password credential of the user The ID of the password credential Time of creation of the password credential Time of last update of the password credential Time of last update of the user The username of the user The ID of the username The actual username of the user Time of creation of the username Time of last update of the username Registered WebAuthn credentials (passkeys and security keys) of the user The ID authenticator that created the credential Format in which the signature is represented and the various contextual bindings are incorporated into the attestation statement by the authenticator Indicates whether the credential may be backed up in some fashion such that they may become present on an authenticator other than their generating authenticator Indicates whether this credential is backed up or not The time of creation of the credential The ID of the credential Indicates when the credential was lst used The public key of the credential (Base64URL string) Communication methods/protocols used to create the credential Indicates whether this is an MFA credential (security key) or a first factor credential (passkey) The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued #### email.send This event is triggered when an email is sent. Subscribe to this event if you want to send customized emails instead of emails based on built-in templates. See [Custom Emails](/guides/email-delivery/email-delivery) for more information. ```json theme={null} { "aud": [ "Test Service ABC" ], "data": { "subject": "Use passcode 325139 to verify your email address", "body_plain": "Enter the following passcode to verify your email address:\n\n325139\n\nThe passcode is valid for 5 minutes.", "to_email_address": "test@example.com", "delivered_by_hanko": false, "language": "en", "type": "passcode", "data": { "service_name": "Test Service ABC", "otp_code": "325139", "ttl": 300, "valid_until": 1737128997 } }, "evt": "email.send", "exp": 1737128997, "iat": 1737128697, "sub": "hanko webhooks" } ``` The recipients the token is intended for The subject line of the email The plain text version of the email body The HTML version of the email body (nullable) The recipient’s email address Indicates whether the email was delivered by Hanko (`true`) or not (`false`). Deprecated, rely on `language` instead. The preferred language for the email content. The preferred language for the email content. The type of the email being sent or to be sent. Available options: `login`, `email_login_attempted`, `email_registration_attempted`, `email_verification`, `recovery`, `security_notification` Additional data. The name of the service set in the Console as the project name The passcode the user can use to log in The validity duration of the passcode in seconds The Unix timestamp indicating when the passcode expires The event that triggered the webhook containing this data The expiration date of the token The time at which the token was issued # Core components Source: https://docs.hanko.io/hanko-authenticator/core-components The core components that make up the Hanko Authenticator, a self-hostable MFA and push authentication solution. ## Hanko Authenticator apps To confirm a sign-in or a second-factor prompt, your users need a device that can sign the request — an authenticator. Typically that's their own smartphone, but it could also be a computer or a second-factor device like a USB security key. To make this easy to roll out, Hanko offers production-ready, white-label authenticator apps for Android and iOS that plug into your application. By simply touching the device's fingerprint sensor or using facial recognition, your users get a fast, secure second factor without typing OTP codes or waiting for SMS. Read more about the [Hanko Authenticator apps](/hanko-authenticator/guides/authenticator-apps) or start with the [getting started guide](/hanko-authenticator/quickstart/authenticator-app). The unbranded/Hanko-branded Android app is currently not available on the Google Play store. Contact us for an APK download link. Download on the App Store ## On-device SDKs & plugins If you'd rather build MFA directly into your existing native app instead of relying on a separate authenticator app, Hanko offers a mobile client SDK for both Android and iOS. Read more in the [SDKs section](/hanko-authenticator/sdks/android). If you use Keycloak as your identity and access management solution — for example after migrating off Entra ID or Okta — you can add the Hanko Authenticator as a login option through the [Keycloak plugin](/hanko-authenticator/sdks/keycloak-plugin). # Hanko Authenticator apps Source: https://docs.hanko.io/hanko-authenticator/guides/authenticator-apps Device compatibility for the Hanko Authenticator apps on Android and iOS. To let your users use passwordless authentication, they need access to the Hanko Authenticator application, which handles the cryptographic authentication requests created by the Hanko service. The Hanko Authenticator application is composed of two essential parts: * FIDO software client * Hanko relying party management Whenever a user chooses passwordless authentication as a login method for your service, a (passwordless) registration request is issued. From then on, each subsequent authentication request results in a notification prompting the user to declare consent (usually by touching the fingerprint reader on their device). Afterwards, the Hanko service informs your application about the outcome of the operation, and it is up to you to decide whether the user may gain access to your application. ## Hanko Authenticator for Android The unbranded/Hanko-branded Android app is currently not available on the Google Play store. Contact us for an APK download link. Hanko Authenticator for Android has been tested with the following devices: | Manufacturer | Device | Android version | PIN/Gesture/Password | Fingerprint | Other biometrics | | ------------ | ----------------- | :-------------: | :------------------: | :---------: | :--------------: | | Google | Pixel | 9.0.0 | Yes | Yes | n/a | | Google | Pixel XL | 9.0.0 | Yes | Yes | n/a | | Google/LG | Nexus 5X | 8.1.0 | Yes | Yes | n/a | | Huawei | P10 | 8.0.0 | Yes | Yes | n/a | | OnePlus | Two | 6.0.1 | Yes | Yes | n/a | | Samsung | Galaxy S8 | 8.0.0 | Yes | Yes | Iris | | Samsung | Galaxy S7 | 8.0.0 | Yes | Yes | n/a | | Samsung | Galaxy J7 | 8.1.0 | Yes | n/a | n/a | | Samsung | Galaxy Xcover4 | 7.0.0 | Yes | n/a | n/a | | Samsung | Galaxy Xcover3 | 6.0.1 | Yes | n/a | n/a | | Sony | Xperia Z5 Compact | 8.0.0 | Yes | Yes | n/a | | Sony | Xperia Z3 Compact | 6.0.1 | Yes | n/a | n/a | Hanko Authenticator for Android requires Android 6.0 or newer. ## Hanko Authenticator for iOS Download on the App Store Hanko Authenticator for iOS has been tested with the following devices: | Device | iOS version | PIN | Touch ID | Face ID | | ------------- | :---------: | :-: | :------: | :-----: | | iPhone XS | 13.3.1 | Yes | n/a | Yes | | iPhone X | 13.3.1 | Yes | n/a | Yes | | iPhone 8 Plus | 13.3.1 | Yes | Yes | n/a | | iPhone 8 | 13.3.1 | Yes | Yes | n/a | | iPhone 7 Plus | 13.3.1 | Yes | Yes | n/a | | iPhone 7 | 13.3.1 | Yes | Yes | n/a | | iPhone 6 | 12 | Yes | Yes | n/a | | iPhone 5S | 12 | Yes | Yes | n/a | | iPhone 5 | 10 | Yes | n/a | n/a | If the iOS device does not have Touch ID or Face ID capabilities, PIN authentication can be used instead. Hanko Authenticator for iOS requires iOS 10 or newer. # Integration guide Source: https://docs.hanko.io/hanko-authenticator/guides/integration-overview What to consider when integrating the Hanko Authenticator into your existing application. As a relying party planning to implement the Hanko Authenticator, one of the major decisions to make is selecting the authentication methods that best fit your business' needs and requirements. This choice is often constrained by: * usability considerations * existing infrastructure (e.g. platform/browser/device availability) * cost considerations (e.g. provision of authenticator devices) * legal requirements or other regulations Once you have decided to use the Hanko Authenticator, there are a number of aspects to consider when integrating it into your application: Assuming your application already has some form of user management that allows users to register and log in to existing accounts, adding the Hanko Authenticator requires modifications to your existing registration flow, both on the client and server side. In addition to modifications to your registration flow, you'll also need to adjust your existing login flow. Using external authenticator devices like smartphones inevitably raises the question of what happens in case of device loss, which makes implementing proper account recovery techniques a primary concern. # Modifying your login flow Source: https://docs.hanko.io/hanko-authenticator/guides/login-screen How to add Hanko Authenticator login to your existing login flow. Once you decide to offer authentication through the Hanko Authenticator, there are a number of modifications required to your existing login flow. This section provides suggestions on how to adjust your existing application to accommodate the required changes. ## Login with the Hanko Authenticator After the user selects the Hanko Authenticator for logging in, initialize the process as described in the [getting started guide](/hanko-authenticator/quickstart/authenticator-app-authentication). Because the Hanko Authenticator uses out-of-band communication, the API will trigger a push notification to the user's previously registered device after initialization. Interacting with the notification opens the Authenticator app and prompts the user to confirm the login request. Because the original client needs to be updated about the login request status, use a fixed-delay polling mechanism in your application after triggering the login request, in order to retrieve the status of the request through the `{API_URL}/v1/uaf/requests/{id}` endpoint. During out-of-band communication, provide visual feedback in the originating client — for example a loading spinner — and redirect to the user's profile or an error page once polling resolves the request status to an `OK` or `FAILED` state. Login out-of-band with the Hanko Authenticator ## Remembering devices via cookies or local storage Consider the following scenario: a user logged out of your application, or was logged out due to an expired session, and now wants to log in again. The user provides an e-mail address and hits "Login". You could then offer a view for selecting the authenticator type to use for logging in, but this requires the user to perform these steps on every login. You can provide a more seamless experience by remembering registered devices on the client side, e.g. using cookies or the browser's local storage. Once the user attempts to log in, use this device information to automatically trigger authentication with the previously used authenticator. One way to approach this is to use the `deviceID` contained in the Hanko request the Hanko API responds with on registration. After a successful registration, extract the `deviceID` from the Hanko request and store it in a cookie or local storage. The next time the user logs in, first use the device management API to get a list of all registered devices for the user, then compare this list with the device information in the cookie or local storage. If there is a match, trigger authentication with that device. If there is no match — for example if the user logs in from a different browser or deleted the cookie/local storage data — fall back to the authenticator selection view. # Recovery techniques Source: https://docs.hanko.io/hanko-authenticator/guides/recovery Strategies for handling lost or unavailable Hanko Authenticator devices. Just as with passwords, users may lose their authentication device. If they cannot access the device used with the Hanko Authenticator, they are unable to log in to your application. In such cases, you will probably want to offer certain recovery strategies to allow them to reset or re-register their devices. This section covers some common strategies to consider when integrating with Hanko. It's advisable to require your users to register at least two authenticator devices, to mitigate device loss scenarios. When prompting the user to authenticate with the Hanko Authenticator, provide a link to reset the authentication method — usually accomplished by sending the user an e-mail with instructions on how to perform account recovery. If you have a strict security policy in place, you might consider further legitimation (e.g. via phone). Recovery link Prompt the user (e.g. through a modal) to provide an e-mail address for recovery. If your login flow has the user input an e-mail before choosing an authenticator type, you can use this information to pre-fill the prompt; otherwise let the user input a custom e-mail address. Recovery e-mail prompt One option for offering re-registration of devices is to embed the QR code used for [registration](/hanko-authenticator/quickstart/authenticator-app-registration) in the recovery e-mail, so users can register a device directly. Another option is to simply embed a link to generate a fresh QR code. Both options require communication with the Hanko API beforehand: you'll need to initialize a registration request to obtain a Hanko request and extract the QR code link from it. Keep in mind that the validity of requests is subject to timeout constraints (default: 120 seconds), which is configurable in your Hanko Authenticator API instance. # Modifying your registration flow Source: https://docs.hanko.io/hanko-authenticator/guides/registration-screen How to add Hanko Authenticator registration to your existing registration flow. Once you decide to offer authentication through the Hanko Authenticator, there are a number of modifications required to your existing registration flow. This section provides suggestions on how to adjust your existing application to accommodate the required changes. Let's assume you want to enable passwordless authentication and offer your users the choice to register with the Hanko Authenticator. You are of course free to choose what authentication methods you want to use when integrating with Hanko. This assumption is only made to exemplify how integration would look. ## Add a view for scanning a QR code Using the Hanko Authenticator involves out-of-band communication and requires the user to scan a QR code with the Hanko Authenticator app on their mobile device during registration. After the user selects the Hanko Authenticator for registration, initialize the process as described in the [getting started guide](/hanko-authenticator/quickstart/authenticator-app-registration). The API response provides a link for generating a QR code. Use the link to generate the QR code and display it to the user (e.g. through a modal, as depicted below). Scanning the code with the Hanko Authenticator kicks off the out-of-band communication between the user's mobile device and the Hanko API. Because the original client needs to be updated about the registration request status, use a fixed-delay polling mechanism in your application after prompting the QR code, in order to retrieve the status of the request through the `{API_URL}/v1/uaf/requests/{id}` endpoint. Once the status resolves to either an `OK` or `FAILED` state, redirect to an appropriate page (e.g. a user profile) or to an error page. Registration via QR code with the Hanko Authenticator # Introduction to Hanko Authenticator Source: https://docs.hanko.io/hanko-authenticator/introduction A self-hostable push authentication app and API for adding MFA, second-factor, and passwordless login to your application. The **Hanko Authenticator** adds strong multi-factor authentication (MFA) to your application: white-label push authentication and passwordless mobile login, similar to Microsoft Authenticator or DUO Security, that you can self-host or run in the EU. It's a common choice for teams that need a self-hosted or EU-hosted MFA solution — for example when migrating an identity stack from Entra ID or Okta to a self-hosted Keycloak, where the [Hanko Keycloak plugin](/hanko-authenticator/sdks/keycloak-plugin) adds the Hanko Authenticator as a login option. You can add it to your application in one of two ways: * a white-label **Hanko Authenticator mobile app** that confirms sign-ins out-of-band, via QR code or push notification, or * the **Hanko FIDO UAF Client SDK**, which embeds the same biometric/PIN confirmation directly into your own native Android or iOS app. Both approaches talk to the same Hanko API and are built on Hanko's certified FIDO UAF server — the open authentication standard behind the cryptography, covered in more detail on the [FIDO UAF background page](/hanko-authenticator/what-is-fido-uaf). The Hanko Authenticator API isn't provisioned through the Hanko Cloud Console yet, and we don't currently run it as a production service — only a test instance is available. [Contact us](mailto:info@hanko.io) for test access. Most customers running the Hanko Authenticator today self-host the API. ## Use cases ### Push authentication with the Hanko Authenticator app The Hanko Authenticator app gives your users a customizable, white-label second factor: after starting a sign-in or a sensitive transaction, they confirm it with a biometric gesture or PIN on their phone — no OTP codes to type, no SMS to wait for. Confirmation happens "out-of-band" — over a channel separate from the one used to sign in: a user starts the process on their desktop and confirms it on their phone in response to a QR code or push notification. Hanko Authenticator out-of-band use case Because confirmation happens on the phone, users don't need a desktop with built-in biometrics or a hardware security key — any desktop with a browser works. [Get started with the Hanko Authenticator app](/hanko-authenticator/quickstart/authenticator-app) ### On-device MFA with the FIDO UAF Client SDK If you'd rather build second-factor or passwordless authentication directly into your own native mobile app instead of directing users to a separate authenticator app, use the Hanko FIDO UAF Client SDK for Android and iOS. Unlike the Hanko Authenticator app, everything happens on-device: all communication originates from your app and runs through your backend to the Hanko API — there's no separate out-of-band channel involved. Hanko FIDO UAF Client on-device use case [Get started with the Hanko FIDO UAF Client for Android or iOS](/hanko-authenticator/quickstart/uaf-client) ## Next steps Understand the pieces that make up the Hanko Authenticator service. Register and authenticate devices with the out-of-band mobile app. Add on-device FIDO UAF authentication to your native Android or iOS app. Optional background reading on the FIDO UAF protocol behind the Hanko Authenticator. # Getting started with Hanko Authenticator Source: https://docs.hanko.io/hanko-authenticator/quickstart/authenticator-app Prerequisites and setup for registering, authenticating, and de-registering devices with the Hanko Authenticator app. This guide demonstrates how you can use the Hanko API and Hanko Authenticator to * [**REGISTER**](/hanko-authenticator/quickstart/authenticator-app-registration) a device * [**AUTHENTICATE**](/hanko-authenticator/quickstart/authenticator-app-authentication) with a device * [**CONFIRM TRANSACTIONS**](/hanko-authenticator/quickstart/authenticator-app-transactions) with a device * [**DEREGISTER**](/hanko-authenticator/quickstart/authenticator-app-de-registration) a device Note that this section is not accompanied by a sample application. We will use manual HTTP requests using an HTTP client to exemplify the required interactions with the Hanko API. For the purpose of properly contextualizing the processes, we still assume the participation of a relying party application. ## Prerequisites You will need: * access to the Hanko Authentication API, which is currently not publicly available. To request test access, please contact us at [info@hanko.io](mailto:info@hanko.io). * an HTTP client to send requests to our API (the following sections include examples using [HTTPie](https://httpie.org/) and [curl](https://curl.haxx.se/)) * the Hanko Authenticator app to register an account: The unbranded/Hanko-branded Android app is currently not available on the Google Play store. Contact us for an APK download link. Download on the App Store You can view a list of supported devices on the [Authenticator Apps page](/hanko-authenticator/guides/authenticator-apps) # Authenticate with a device using Hanko Authenticator Source: https://docs.hanko.io/hanko-authenticator/quickstart/authenticator-app-authentication How to authenticate a registered device through the Hanko API and the Hanko Authenticator app. In order to authenticate with a device through the Hanko API using the Hanko Authenticator apps, the following three steps must be performed: * [**Step 1**](#step-1-retrieve-an-authentication-request): Retrieve an authentication request * [**Step 2**](#step-2-confirm-the-authentication-request): Confirm the authentication request through the Hanko Authenticator via out-of-band communication * [**Step 3**](#step-3-verify-successful-authentication): Use the Hanko API to verify successful authentication Hanko Authenticator authentication flow *** ## Step 1: Retrieve an authentication request First we need to initiate the authentication of an authenticator device by issuing a `POST` request to the UAF endpoint (`{API_URL}/v1/uaf/requests`) of the Hanko API. The `POST` request body must include the appropriate `operation` type (i.e. `AUTH` for authentication), a `userId` and a `username`. ```bash cURL theme={null} curl -X POST "{API_URL}/v1/uaf/requests" \ -H 'Authorization:secret pasteYourApiKeyHere' \ -H 'Content-Type: application/json' \ -d '{"operation": "AUTH", "username":"example@example.com", "userId":"exampleId" }' ``` ```bash HTTPie theme={null} http POST {API_URL}/v1/uaf/requests \ 'Authorization:secret pasteYourApiKeySecretHere' \ 'operation=AUTH' \ 'username=example@example.com' \ 'userId=exampleId' ``` The API will respond with a Hanko request indicating that the authentication is currently `PENDING`. The `links` section of the Hanko request contains an API endpoint reference that allows us to retrieve a status of the Hanko request. We will later use this to verify whether the authentication process was successful. ```json theme={null} { "id": "HzZqumLjNYZ29PNwEkzFQHuAF6U0kmW2oEuzchFtUJIF", "operation": "AUTH", "status": "PENDING", "userId": "exampleId", "username": "example@example.com", "links": [ { "href": "{API_URL}/v1/uaf/requests/HzZqumLjNYZ29PNwEkzFQHuAF6U0kmW2oEuzchFtUJIF", "method": "GET", "rel": "result" } ], ..., } ``` *** ## Step 2: Confirm the authentication request The Hanko API will send a push notification to our mobile device which triggers the Hanko Authenticator to inform us that an authentication request was initiated and prompt us to confirm that we initiated the authentication request. To continue with the authentication process: 1. The Hanko Authenticator will display metadata pertaining to the authentication request (e.g. date, geo-location of the request origin) and prompt you to confirm the authentication request to ensure that it was indeed you who initiated the authentication process. 2. The Hanko Authenticator will then retrieve the current pending authentication request from the Hanko API and provide the authenticator with the FIDO server challenge contained in the request. 3. When prompted, perform an authentication gesture either by using the biometric capabilities of your mobile devices or - if your mobile device does not have any biometric capabilities - provide the mobile device PIN. 4. The Hanko Authenticator will return the UAF authenticator response including the signed challenge from the initial FIDO request and validate and finalize the authentication request. *** ## Step 3: Verify successful authentication We can verify that the authentication was successful by using the `status` link contained in the Hanko request we retrieved in [Step 1](#step-1-retrieve-an-authentication-request). ```json theme={null} { "href": "{API_URL}/v1/uaf/requests/csBMTswnVm11PcC7OgOVm5s9a6uwoCxEyoYul1Fr3csF", "method": "GET", "rel": "status" } ``` If successful, the `status` property of the returned Hanko request should be `OK`. ```json theme={null} { "id": "csBMTswnVm11PcC7OgOVm5s9a6uwoCxEyoYul1Fr3csF", "operation": "AUTH", "status": "OK", "userId": "exampleId", "username": "example@example.com", ..., } ``` Note that the interactions in [Step 2](#step-2-confirm-the-authentication-request) were based on out-of-band communication. This means that an authentication flow as depicted above would usually require the relying party application to somehow become aware of the outcome of the authentication process so that the original client accessing the application can be informed and updated. One way to achieve this is to continually poll the request Hanko request until a `status` change can be detected. ```bash cURL theme={null} curl -X GET "{API_URL}/v1/uaf/requests/{id}" \ -H 'Authorization:secret pasteYourApiKeySecretHere' \ -H 'Content-Type: application/json' ``` ```bash HTTPie theme={null} http GET {API_URL}/v1/uaf/requests/{id} \ 'Authorization:secret pasteYourApiKeySecretHere' ``` # De-register a device Source: https://docs.hanko.io/hanko-authenticator/quickstart/authenticator-app-de-registration How to de-register one, several, or all Hanko Authenticator devices for a user through the Hanko API. You can use the Hanko API to de-register authenticator devices registered through Hanko Authenticator. Device de-registration need not be finalized, i.e. it does *not* require any additional out-of-band interaction apart from issuing an initial de-registration request. Depending on whether the `userId` associated with the devices you want to de-register exists or not, the entire de-registration operation is either `OK` or `FAILED` and therefore completed after the initialization step. You can either de-register all authenticator devices for a user or you can de-register specific authenticator devices. ### De-Register all devices for a user To de-register all authenticator devices for a user issue a `POST` request to the UAF endpoint (`{API_URL}/v1/uaf/requests`) of the Hanko API. You must provide the `userId` and the `username` of the user the authenticator devices are associated with as well as the appropriate `operation` type (`DEREG`). ```bash cURL theme={null} curl -X POST "{API_URL}/v1/uaf/requests" \ -H 'Authorization:secret pasteYourApiKeyHere' \ -H 'Content-Type: application/json' \ -d '{"operation": "DEREG", "username":"example@example.com", "userId":"exampleId" }' ``` ```bash HTTPie theme={null} http POST {API_URL}/v1/uaf/requests \ 'Authorization:secret pasteYourApiKeySecretHere' \ 'operation=DEREG' \ 'username=example@example.com' \ 'userId=exampleId' ``` The API should respond with a Hanko request, the `status` property indicating whether the de-registration process was successful (`OK`) or not (`FAILED`). ```json theme={null} { "id": "HzZqumLjNYZ29PNwEkzFQHuAF6U0kmW2oEuzchFtUJIF", "operation": "DEREG", "status": "OK", "userId": "exampleId", "username": "example@example.com", ... } ``` ### De-Register specific devices for a user To de-register specific authenticator devices for a user, issue a `POST` request to the UAF endpoint (`{API_URL}/v1/uaf/requests`) of the Hanko API. You must provide the `userId` and the `username` of the user the authenticator devices are associated with as well as the appropriate `operation` type (`DEREG`). To further specify the devices to de-register, include a comma-separated list of device ID strings under the `deviceIds` key in the request body. If you are unsure how to get the registered `deviceIds` of a user: you can always use the device management capabilities of the API to get the registered devices for a user, including the `deviceId` required for the de-registration process described above. When using IDs from the device list returned through this endpoint for de-registration, make sure you use only devices of the appropriate `authenticator_type`, i.e. `FIDO_UAF`. ```bash theme={null} curl --location --request POST '{API_URL}/v1/uaf/requests' \ --header 'Authorization: secret pasteYourApiKeyHere' \ --header 'Content-Type: application/json' \ --data-raw '{ "operation": "DEREG", "userId": "exampleId", "username": "example@example.com", "deviceIds": ["exampleDevice", "anotherExampleDevice"] }' ``` The API should respond with a Hanko request. The `status` property indicates whether the de-registration process was successful (`OK`) or not (`FAILED`). ```json theme={null} { "id": "HzZqumLjNYZ29PNwEkzFQHuAF6U0kmW2oEuzchFtUJIF", "operation": "DEREG", "status": "OK", "userId": "exampleId", "username": "example@example.com", ... } ``` # Register a device using the Hanko Authenticator Source: https://docs.hanko.io/hanko-authenticator/quickstart/authenticator-app-registration How to register an authenticator device through the Hanko API and the Hanko Authenticator app. In order to register a device through the Hanko API using the Hanko Authenticator apps, the following three steps must be performed: * [**Step 1**](#step-1-retrieve-a-registration-request): Retrieve a registration request * [**Step 2**](#step-2-confirm-the-registration-request): Confirm the registration request through the Hanko Authenticator via out-of-band communication * [**Step 3**](#step-3-verify-successful-registration): Use the Hanko API to verify successful registration Hanko Authenticator registration flow *** ## Step 1: Retrieve a registration request First we need to initiate the registration of an authenticator device by issuing a `POST` request to the UAF endpoint (`{API_URL}/v1/uaf/requests`) of the Hanko API. The `POST` request body must include the appropriate `operation` type (i.e. `REG` for registration), a `userId` and a `username`. ```bash cURL theme={null} curl -X POST "{API_URL}/v1/uaf/requests" \ -H 'Authorization:secret pasteYourApiKeyHere' \ -H 'Content-Type: application/json' \ -d '{"operation": "REG", "username":"example@example.com", "userId":"exampleId" }' ``` ```bash HTTPie theme={null} http POST {API_URL}/v1/uaf/requests \ 'Authorization:secret pasteYourApiKeySecretHere' \ 'operation=REG' \ 'username=example@example.com' \ 'userId=exampleId' ``` The API will respond with a Hanko request indicating that the registration is currently `PENDING`. The `links` section of the Hanko request contains an API endpoint reference that allows us to retrieve a `qrcode`. We will use this in the next step to initiate communication through an "out-of-band" communication channel. The `status` link will allow the relying party application to test if registration via this out-of-band communication was successful or not. ```json theme={null} { "id": "csBMTswnVm11PcC7OgOVm5s9a6uwoCxEyoYul1Fr3csF", "operation": "REG", "status": "PENDING", "userId": "exampleId", "username": "example@example.com", "links": [ { "href": "{API_URL}/v1/uaf/requests/csBMTswnVm11PcC7OgOVm5s9a6uwoCxEyoYul1Fr3csF/qrcode", "method": "GET", "rel": "qrcode" }, { "href": "{API_URL}/v1/uaf/requests/csBMTswnVm11PcC7OgOVm5s9a6uwoCxEyoYul1Fr3csF", "method": "GET", "rel": "status" } ], ..., } ``` *** ## Step 2: Confirm the registration request In order to complete the registration we use the `qrcode` link from the Hanko request returned during initialization. Using the QR code initiates out-of-band communication, which simply means that we use a communication channel different from the one used to access the relying party application. Notice that in the figure above all interactions for this step happen between the user's mobile device (running the Hanko Authenticator app) and the Hanko API only. Furthermore, note that in the idealized registration flow depicted above the relying party application frontend would normally take on the task of displaying the QR code to the user. In this guide we will get the QR code manually in order to continue the registration process: 1. Open the `qrcode` link in your browser. 2. Open the [Hanko Authenticator](/hanko-authenticator/guides/authenticator-apps) app on your mobile device 3. Tap `Add Account` and scan the displayed QR code using your mobile device. The Hanko Authenticator will retrieve the current pending registration request from the Hanko API and provide the authenticator with the FIDO server challenge contained in the request. 4. The Hanko Authenticator will display metadata pertaining to the registration request (e.g. date, geo-location of the request origin) and prompt you to confirm the registration request to ensure that it was indeed you who initiated the registration process. 5. Perform an authentication gesture either by using the biometric capabilities of your mobile devices or - if your mobile device does not have any biometric capabilities - provide the mobile device PIN. 6. The Hanko Authenticator will return the UAF authenticator response and validate and finalize the registration request. ```json theme={null} { "href": "{API_URL}/v1/uaf/requests/csBMTswnVm11PcC7OgOVm5s9a6uwoCxEyoYul1Fr3csF/qrcode", "method": "GET", "rel": "qrcode" } ``` *** ## Step 3: Verify successful registration We can verify that the registration was successful by using the `status` link contained in the Hanko request we retrieved in [Step 1](#step-1-retrieve-a-registration-request). ```json theme={null} { "href": "{API_URL}/v1/uaf/requests/csBMTswnVm11PcC7OgOVm5s9a6uwoCxEyoYul1Fr3csF", "method": "GET", "rel": "status" } ``` If successful, the `status` property of the returned Hanko request should be `OK`. ```json theme={null} { "id": "csBMTswnVm11PcC7OgOVm5s9a6uwoCxEyoYul1Fr3csF", "operation": "REG", "status": "OK", "userId": "exampleId", "username": "example@example.com", ..., } ``` Note that the interactions in [Step 2](#step-2-confirm-the-registration-request) were based on out-of-band communication. This means that a registration flow as depicted above would usually require the relying party application to somehow become aware of the outcome of the registration process so that the original client accessing the application can be informed and updated. One way to achieve this is to continually poll the request Hanko request until a `status` change can be detected. ```bash cURL theme={null} curl -X GET "{API_URL}/v1/uaf/requests/{id}" \ -H 'Authorization:secret pasteYourApiKeySecretHere' \ -H 'Content-Type: application/json' ``` ```bash HTTPie theme={null} http GET {API_URL}/v1/uaf/requests/{id} \ 'Authorization:secret pasteYourApiKeySecretHere' ``` # Confirm transactions using Hanko Authenticator Source: https://docs.hanko.io/hanko-authenticator/quickstart/authenticator-app-transactions How to add a transaction detail to an authentication request so users can confirm it with the Hanko Authenticator app. The process for confirming transactions with the Hanko Authenticator is essentially the same as for the regular [authentication](/hanko-authenticator/quickstart/authenticator-app-authentication) process. The main difference between the two is that when *initializing* the request you need to supply a request body with an additional `transaction` attribute. Its value is a transaction text that is part of the request metadata displayed in the confirmation prompt during [out-of-band communication](/hanko-authenticator/quickstart/authenticator-app-authentication#step-2-confirm-the-authentication-request). It also becomes part of the challenge issued by the FIDO server and hence the signature created in the course of the authentication process. ```bash cURL theme={null} curl -X POST "{API_URL}/v1/uaf/requests" \ -H 'Authorization:secret pasteYourApiKeyHere' \ -H 'Content-Type: application/json' \ -d '{"operation": "AUTH", "username":"example@example.com", "userId":"exampleId", "transaction": "Transfer $100 to Mike?" }' ``` ```bash HTTPie theme={null} http POST {API_URL}/v1/uaf/requests \ 'Authorization:secret pasteYourApiKeySecretHere' \ 'operation=AUTH' \ 'username=example@example.com' \ 'userId=exampleId' \ 'transaction=Transfer $100 to Mike?' ``` # Getting started with the Hanko FIDO UAF Client Source: https://docs.hanko.io/hanko-authenticator/quickstart/uaf-client Prerequisites and setup for integrating the Hanko FIDO UAF Client into your native Android or iOS app. This guide demonstrates how to use the Hanko FIDO UAF Client and the Hanko API to perform **on-device** authentication. Unlike using the Hanko Authenticator, this scenario does not involve out-of-band communication. Instead of initiating communication on a desktop through a browser and confirming authentication in response to out-of-band notifications on a mobile device, *all* communication originates from the mobile device and runs through an application backend which passes information to the Hanko API. In this guide you will learn how to * [**REGISTER**](/hanko-authenticator/quickstart/uaf-client-registration) a device * [**AUTHENTICATE**](/hanko-authenticator/quickstart/uaf-client-authentication) with a registered device * [**CONFIRM TRANSACTIONS**](/hanko-authenticator/quickstart/uaf-client-transactions) with a device * [**DEREGISTER**](/hanko-authenticator/quickstart/uaf-client-de-registration) a device using the Hanko FIDO UAF Client. ## Prerequisites ### Add the Hanko FIDO UAF Client as a project dependency * min. android SDK version: 23 * a secure keyguard (biometrics, pin, pattern, etc.) To add the Hanko FIDO UAF Client to your Android project, add the following line to your `build.gradle`: ``` implementation 'io.hanko:fidouafclient:' ``` Replace `` with the latest version. The latest version can be found [here](https://github.com/teamhanko/fidouafclient/tags). **Using Carthage**: To integrate FidoUafClientiOS into your Xcode project using Carthage, specify it in your Cartfile: ``` github 'teamhanko/fidouafclientiOS' == '' ``` **Using CocoaPods**: To integrate FidoUafClientiOS into your project using CocoaPods, specify it in your Podfile: ``` pod 'FidoUafClientiOS', ``` Replace `` with the latest version. The latest version can be found [here](https://github.com/teamhanko/fidouafclientiOS/tags). ### HTTP client library In order to make HTTP requests the relying party backend can proxy to the Hanko API, you need a suitable HTTP client library (e.g. [OkHttp](https://square.github.io/okhttp/) for Android, [Alamofire](https://github.com/Alamofire/Alamofire) for iOS). ### Hanko server-side SDK To forward HTTP requests to the Hanko API you can use one of our server-side SDKs in your backend application. Backend SDK examples for this step will be added once official server SDKs are available. ### Configuration **Client availability across apps** The FIDO UAF Client is only available for your app. You can make it publicly available for all apps on the device. Add the following to your `AndroidManifest.xml`: ```xml theme={null} ``` **Face ID usage** FidoUafClientiOS uses FaceID, so you must define `NSFaceIDUsageDescription` in your `Info.plist`. **Operation prompts** The FidoUafClientiOS uses default values to display `kSecUseOperationPrompt` when using the private keys. The default values are localized to English and German. To override the default values just add the keys `biomentryOperationPromptReg` and `biomentryOperationPromptAuth` to your project's `Localizable.strings`. If a request contains a transaction, the `biomentryOperationPromptAuth` will be overridden with the transaction content. ### Customization **Operation prompts** To customize the strings which are displayed during registration and authentication, define the following strings in your strings `.xml` file: ```xml theme={null} Register Authenticate Authenticate to create a key Authenticate to use a key Choose your key ``` **Operation prompts** The FidoUafClientiOS uses default values to display kSecUseOperationPrompt when using the private keys. The default values are localized to English and German. To override the default values just add the keys `biomentryOperationPromptReg` and `biomentryOperationPromptAuth` to your project's `Localizable.strings`. Note: If a request contains a transaction the `biomentryOperationPromptAuth` will be overridden with the transaction content. ## Obtain an API Key You need access to the Hanko Authentication API, which is currently not publicly available. To request test access, please contact us at [info@hanko.io](mailto:info@hanko.io). # Authenticate with a device using the Hanko FIDO UAF Client Source: https://docs.hanko.io/hanko-authenticator/quickstart/uaf-client-authentication Authenticate with a previously registered device on-device using the Hanko FIDO UAF Client and the Hanko API. In order to authenticate with a device using the Hanko FIDO UAF Client and the Hanko API, the following three steps must be performed: * **Step 1**: Retrieve an authentication request * **Step 2**: Pass the authentication request to the Hanko FIDO UAF Client * **Step 3**: Send the public key to the Hanko API Hanko FIDO UAF Client authentication flow ## Step 1: Retrieve an authentication request The first step consists of initiating the authentication by issuing a `POST` request to the UAF endpoint (`{API_URL}/v1/uaf/requests`) of the Hanko API. The `POST` request body must include the appropriate operation type (i.e. `AUTH` for authentication), a `userId` and a `username`. The userId will be used to map a public key credential generated during registration to a specific user account with the relying party. As mentioned in the [prerequisites](/hanko-authenticator/quickstart/uaf-client), you need an HTTP client to make a request to your backend. In your backend you can use one of the server-side Hanko SDKs to initiate the authentication with the Hanko API. This request targets a secured endpoint of the API, so you will need an API Key ID and an API Key (see the [prerequisites](/hanko-authenticator/quickstart/uaf-client)). ```bash httpie theme={null} http POST {API_URL}/v1/uaf/requests \ 'Authorization:secret pasteYourApiKeySecretHere' \ 'operation=AUTH' \ 'username=example@example.com' \ 'userId=exampleId' ``` ```bash cURL theme={null} curl -X POST "{API_URL}/v1/uaf/requests" \ -H 'Authorization:secret pasteYourApiKeyHere' \ -H 'Content-Type: application/json' \ -d '{"operation": "AUTH", "username":"example@example.com", "userId":"exampleId" }' ``` The API will respond with a Hanko request in a `PENDING` status. It contains the authentication `request` issued by the FIDO server which must be passed to the Hanko FIDO UAF Client in order to trigger authentication through an authentication gesture. ```json theme={null} { "id": "", "request": "", "operation": "AUTH", "username": "example@example.com", "userId": "exampleId", "status": "PENDING", ... } ``` Remember to cache the returned Hanko request because the request `id` will be required to finalize the registration in Step 3. ## Step 2: Pass the authentication request to the Hanko FIDO UAF Client Extract the `request` value from the Hanko request you retrieved in the previous step and use Android's Intent mechanism to pass it to the Hanko FIDO UAF Client. This will start an activity which will trigger the prompt for an authentication gesture. To retrieve the activity result, use the [`startActivityForResult()`](https://developer.android.com/reference/android/app/Activity#startActivityForResult\(android.content.Intent,%20int,%20android.os.Bundle\)) API. ```java theme={null} Intent intent = new Intent(context, io.hanko.fidouafclient.FidoUafClient.class); intent.setType("application/fido.uaf_client+json"); intent.putExtra("UAFIntentType", "UAF_OPERATION"); intent.putExtra("channelBindings", "{}"); intent.putExtra("message", ""); startActivityForResult(intent, REQUEST_CODE); ``` After the user accepted or denied the request by performing an authentication gesture, you can process the result using the [`onActivityResult`](https://developer.android.com/reference/android/app/Activity#onActivityResult\(int,%20int,%20android.content.Intent\)) API. ```java theme={null} protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(resultCode == RESULT_OK && requestCode == REQUEST_CODE) { short errorCode = data.getShortExtra("errorCode", (short) 0xFF); if(errorCode == 0x00) { // errorCode 0x00 means success try { JSONObject jsonObject = new JSONObject(data.getStringExtra("message")); // 1. String uafResponse = jsonObject.getString("uafProtocolMessage"); // 1. // verify uafResponse } catch(JSONException ex) { // TODO } } else { // some error occured, use errorCode for determination } } } ``` Extract the response (1) from the `Intent` data. The extracted value will be used in the next step to verify the authenticator response. Extract the `request` value from the Hanko request you retrieved in the previous step and create a `UAFMessage` (`` is the `request` value). ```swift theme={null} let uafMessage = UAFMessage(uafProtocolMessage: "") ``` Pass the `UAFMessage` to the client's `process` method. ```swift theme={null} FidoClient.process(uafMessage: uafMessage) { resultMessage, error in // send resultMessage to Hanko API } ``` After the user accepted or denied the request by performing an authentication gesture, send the authenticator response (`resultMessage`) to the Hanko API in the next step. ## Step 3: Send the public key to the Hanko API To finalize the authentication by verifying the authenticator response, use an HTTP client in your app to forward the authenticator response along with the `requestId` to your backend. Then, use a Hanko server-side SDK to pass the authenticator response to the Hanko API. This request targets a secured endpoint so you will need an API Key ID and an API Key. Reuse a previously instantiated client instance or create one as described in Step 1. Backend SDK examples for this step will be added once official server SDKs are available again. # De-register a device using the Hanko FIDO UAF Client Source: https://docs.hanko.io/hanko-authenticator/quickstart/uaf-client-de-registration Remove one or all authenticator devices registered on-device with the Hanko FIDO UAF Client. One of the main differences between de-registration and registration/authentication is that de-registration does *not* require the usual sequence of initializing and finalizing/validating the de-registration request, i.e. you do not have to finalize the de-registration request with the Hanko API. Depending on whether the `userId` associated with the devices you want to de-register exists or not, the entire de-registration operation is either `OK` or `FAILED` and therefore completed after the initialization step. Just as with registration and authentication though, you will receive a de-registration request in the form of a UAF protocol message upon initialization that must be passed to the FIDO UAF Client in order to de-register the respective credentials on the device. * **Step 1**: Retrieve a de-registration request * **Step 2**: Pass the de-registration request to the Hanko FIDO UAF Client Hanko FIDO UAF Client de-registration flow ## Step 1: Retrieve a de-registration request You can either de-register all authenticator devices for a user or you can de-register specific authenticator devices. ### De-register all devices To de-register all authenticator devices for a user, issue a `POST` request to the UAF endpoint (`{API_URL}/v1/uaf/requests`) of the Hanko API. You must provide the `userId` and the `username` of the user the authenticator devices are associated with as well as the appropriate `operation` type (`DEREG`). ```bash httpie theme={null} http POST {API_URL}/v1/uaf/requests \ 'Authorization:secret pasteYourApiKeySecretHere' \ 'operation=DEREG' \ 'username=example@example.com' \ 'userId=exampleId' ``` ```bash cURL theme={null} curl -X POST "{API_URL}/v1/uaf/requests" \ -H 'Authorization:secret pasteYourApiKeyHere' \ -H 'Content-Type: application/json' \ -d '{"operation": "DEREG", "username":"example@example.com", "userId":"exampleId" }' ``` The API should respond with a Hanko request, the `status` property indicating whether the de-registration process was successful (`OK`) or not (`FAILED`). It will also contain the `request` issued by the FIDO server which will be used in the next step. ```json theme={null} { "id": "", "request": "", "operation": "DEREG", "status": "OK", "userId": "exampleId", "username": "example@example.com", ... } ``` ### De-register specific devices To de-register specific authenticator devices for a user, issue a `POST` request to the UAF endpoint (`{API_URL}/v1/uaf/requests`) of the Hanko API. You must provide the `userId` and the `username` of the user the authenticator devices are associated with as well as the appropriate `operation` type (`DEREG`). To further specify the devices to de-register, include a comma-separated list of device ID strings under the `deviceIds` key in the request body. If you are unsure how to get the registered `deviceIds` of a user, you can always use the device management capabilities of the API to get the registered devices for a user, including the `deviceId` required for the de-registration process described above. When using IDs from the device list returned through this endpoint for de-registration, make sure you use only devices of the appropriate `authenticator_type`, i.e. `FIDO_UAF`. ```bash cURL theme={null} curl --location --request POST '{API_URL}/v1/uaf/requests' \ --header 'Authorization: secret pasteYourApiKeyHere' \ --header 'Content-Type: application/json' \ --data-raw '{ "operation": "DEREG", "userId": "exampleId", "username": "example@example.com", "deviceIds": ["exampleDevice", "anotherExampleDevice"] }' ``` The API should respond with a Hanko request. The `status` property indicates whether the de-registration process was successful (`OK`) or not (`FAILED`). It will also contain the `request` issued by the FIDO server which will be used in the next step. ```json theme={null} { "id": "", "request": "", "operation": "DEREG", "status": "OK", "userId": "exampleId", "username": "example@example.com", ... } ``` ## Step 2: Pass the de-registration request to the Hanko FIDO UAF Client Extract the `request` value from the Hanko request you retrieved in the previous step. Create a stringified representation of a JSON object with the following structure: ```json theme={null} { "uafProtocolMessage": "" } ``` Use Android's Intent mechanism to pass it to the Hanko FIDO UAF Client (``). This will trigger a prompt for an authentication gesture. To retrieve the activity result, use the [`startActivityForResult`](https://developer.android.com/reference/android/app/Activity#startActivityForResult\(android.content.Intent,%20int,%20android.os.Bundle\)) API. ```java theme={null} Intent intent = new Intent(context, io.hanko.fidouafclient.FidoUafClient.class); intent.setType("application/fido.uaf_client+json"); intent.putExtra("UAFIntentType", "UAF_OPERATION"); intent.putExtra("channelBindings", "{}"); intent.putExtra("message", ""); startActivityForResult(intent, REQUEST_CODE); ``` After the user accepted or denied the request by performing an authentication gesture, you can process the result using the [`onActivityResult`](https://developer.android.com/reference/android/app/Activity#onActivityResult\(int,%20int,%20android.content.Intent\)) API. ```java theme={null} protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(resultCode == RESULT_OK && requestCode == REQUEST_CODE) { short errorCode = data.getShortExtra("errorCode", (short) 0xFF); if(errorCode == 0x00) { // errorCode 0x00 means success try { JSONObject jsonObject = new JSONObject(data.getStringExtra("message")); // 1. String uafResponse = jsonObject.getString("uafProtocolMessage"); // 1. // verify uafResponse } catch(JSONException ex) { // TODO } } else { // some error occured, use errorCode for determination } } } ``` Extract the response (1) from the `Intent` data. The extracted value will be used in the next step to verify the authenticator response. Extract the `request` value from the Hanko request you retrieved in the previous step and create a `UAFMessage` (`` is the `request` value). ```swift theme={null} let uafMessage = UAFMessage(uafProtocolMessage: "") ``` Pass the `UAFMessage` to the client's `process` method. ```swift theme={null} FidoClient.process(uafMessage: uafMessage) { resultMessage, error in // send resultMessage to Hanko API } ``` After the user accepted or denied the request by performing an authentication gesture, send the authenticator response (`resultMessage`) to the Hanko API in the next step. # Register a device with the Hanko FIDO UAF Client Source: https://docs.hanko.io/hanko-authenticator/quickstart/uaf-client-registration Register an authenticator device on-device using the Hanko FIDO UAF Client and the Hanko API. In order to register a device using the Hanko FIDO UAF Client and the Hanko API, the following three steps must be performed: * **Step 1**: Retrieve a registration request * **Step 2**: Pass the registration request to the Hanko FIDO UAF Client * **Step 3**: Send the public key to the Hanko API Hanko FIDO UAF Client registration flow ## Step 1: Retrieve a registration request The first step consists of initiating the registration of an authenticator device by issuing a `POST` request to the UAF endpoint (`{API_URL}/v1/uaf/requests`) of the Hanko API. The `POST` request body must include the appropriate operation type (i.e. `REG` for registration), a `userId` and a `username`. The userId will be used to map a public key credential generated during registration to a specific user account with the relying party. As mentioned in the [prerequisites](/hanko-authenticator/quickstart/uaf-client), you need an HTTP client to make a request to your backend. In your backend you can use one of the server-side Hanko SDKs to initiate the registration with the Hanko API. This request targets a secured endpoint of the API, so you will need an API Key ID and an API Key (see the [prerequisites](/hanko-authenticator/quickstart/uaf-client)). ```bash httpie theme={null} http POST {API_URL}/v1/uaf/requests \ 'Authorization:secret pasteYourApiKeySecretHere' \ 'operation=REG' \ 'username=example@example.com' \ 'userId=exampleId' ``` ```bash cURL theme={null} curl -X POST "{API_URL}/v1/uaf/requests" \ -H 'Authorization:secret pasteYourApiKeyHere' \ -H 'Content-Type: application/json' \ -d '{"operation": "REG", "username":"example@example.com", "userId":"exampleId" }' ``` The API will respond with a Hanko request in a `PENDING` status. It contains the registration `request` issued by the FIDO server which must be passed to the Hanko FIDO UAF Client in order to trigger credential creation and prompting the user for an authentication gesture. ```json theme={null} { "id": "", "request": "", "operation": "REG", "username": "example@example.com", "userId": "exampleId", "status": "PENDING", ... } ``` Remember to cache the returned Hanko request because the request `id` will be required to finalize the registration in Step 3. ## Step 2: Pass the registration request to the Hanko FIDO UAF Client Extract the `request` value from the Hanko request you retrieved in the previous step. Create a stringified representation of a JSON object with the following structure: ```json theme={null} { "uafProtocolMessage": "" } ``` Use Android's Intent mechanism to pass it to the Hanko FIDO UAF Client (``). This will trigger a prompt for an authentication gesture. To retrieve the activity result, use the [`startActivityForResult`](https://developer.android.com/reference/android/app/Activity#startActivityForResult\(android.content.Intent,%20int,%20android.os.Bundle\)) API. ```java theme={null} Intent intent = new Intent(context, io.hanko.fidouafclient.FidoUafClient.class); intent.setType("application/fido.uaf_client+json"); intent.putExtra("UAFIntentType", "UAF_OPERATION"); intent.putExtra("channelBindings", "{}"); intent.putExtra("message", ""); startActivityForResult(intent, REQUEST_CODE); ``` After the user accepted or denied the request by performing an authentication gesture, you can process the result using the [`onActivityResult`](https://developer.android.com/reference/android/app/Activity#onActivityResult\(int,%20int,%20android.content.Intent\)) API. ```java theme={null} protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(resultCode == RESULT_OK && requestCode == REQUEST_CODE) { short errorCode = data.getShortExtra("errorCode", (short) 0xFF); if(errorCode == 0x00) { // errorCode 0x00 means success try { JSONObject jsonObject = new JSONObject(data.getStringExtra("message")); // 1. String uafResponse = jsonObject.getString("uafProtocolMessage"); // 1. // verify uafResponse } catch(JSONException ex) { // TODO } } else { // some error occured, use errorCode for determination } } } ``` Extract the response (1) from the `Intent` data. The extracted value will be used in the next step to verify the authenticator response. Extract the `request` value from the Hanko request you retrieved in the previous step and create a `UAFMessage` (`` is the `request` value). ```swift theme={null} let uafMessage = UAFMessage(uafProtocolMessage: "") ``` Pass the `UAFMessage` to the client's `process` method. ```swift theme={null} FidoClient.process(uafMessage: uafMessage) { resultMessage, error in // send resultMessage to Hanko API } ``` After the user accepted or denied the request by performing an authentication gesture, send the authenticator response (`resultMessage`) to the Hanko API in the next step. ## Step 3: Send the public key to the Hanko API To finalize the registration by verifying the authenticator response, use an HTTP client in your app to forward the authenticator response along with the `requestId` of the initialization request (see Step 1) to your backend. Then, use a Hanko server-side SDK to pass the authenticator response to the Hanko API. This request targets a secured endpoint so you will need an API Key ID and an API Key. Reuse a previously instantiated client instance or create one as described in Step 1. Backend SDK examples for this step will be added once official server SDKs are available again. After registration is successful you can choose to persist information that a user has registered a device (e.g. using [Shared Preferences](https://developer.android.com/reference/android/content/SharedPreferences), [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults)) such that - for example - subsequent authentication attempts automatically use the registered credential. # Confirm transactions using the Hanko FIDO UAF Client Source: https://docs.hanko.io/hanko-authenticator/quickstart/uaf-client-transactions Bind a transaction to the authentication challenge and confirm it on-device with the Hanko FIDO UAF Client. The process for confirming transactions with the Hanko FIDO UAF Client is essentially the same as for the regular [authentication](/hanko-authenticator/quickstart/uaf-client-authentication) process. The main difference between the two is that when *initializing* the request you need to supply a request body with an additional `transaction` attribute. Its value is a transaction text that becomes part of the challenge issued by the FIDO server and hence the signature created in the course of the authentication process. ```bash httpie theme={null} http POST {API_URL}/v1/uaf/requests \ 'Authorization:secret pasteYourApiKeySecretHere' \ 'operation=AUTH' \ 'username=example@example.com' \ 'userId=exampleId' \ 'transaction=Transfer $100 to Mike?' ``` ```bash cURL theme={null} curl -X POST "{API_URL}/v1/uaf/requests" \ -H 'Authorization:secret pasteYourApiKeyHere' \ -H 'Content-Type: application/json' \ -d '{"operation": "AUTH", "username":"example@example.com", "userId":"exampleId", "transaction": "Transfer $100 to Mike?" }' ``` Once the request has been initiated, pass it to the Hanko FIDO UAF Client and send the response back to the Hanko API exactly as described in the [authentication](/hanko-authenticator/quickstart/uaf-client-authentication) guide. # Cancel the request for the Hanko Authenticator Source: https://docs.hanko.io/hanko-authenticator/reference/cancel-a-request openapi-authenticator delete /v1/uaf/requests/{id} Cancel a previously created Hanko Authenticator operation. # Create a request for the Hanko Authenticator Source: https://docs.hanko.io/hanko-authenticator/reference/create-a-request openapi-authenticator post /v1/uaf/requests Initialize a registration, authentication, or de-registration operation for the Hanko Authenticator. Remember the returned `id` — you'll need it to check the status of, validate, or cancel this operation. # Get the QR code for a given Hanko Authenticator request Source: https://docs.hanko.io/hanko-authenticator/reference/get-a-qr-code openapi-authenticator get /v1/uaf/requests/{id}/qrcode Get a QR code for establishing out-of-band communication via the Hanko Authenticator. # Get the request for the Hanko Authenticator Source: https://docs.hanko.io/hanko-authenticator/reference/get-a-request openapi-authenticator get /v1/uaf/requests/{id} Get the current status of a previously created Hanko Authenticator operation. # Get all devices of a user Source: https://docs.hanko.io/hanko-authenticator/reference/get-a-users-devices openapi-authenticator get /mgmt/v1/registrations/{userId} Get all registered authenticator devices of a user. # Change the name of a authentication device Source: https://docs.hanko.io/hanko-authenticator/reference/rename-a-device openapi-authenticator post /mgmt/v1/registrations/rename/{deviceId} Change the display name of a registered authenticator device. # Validate the request as retrieved from the Hanko Authenticator Source: https://docs.hanko.io/hanko-authenticator/reference/validate-a-request openapi-authenticator put /v1/uaf/requests/{id} Validate the cryptographic response returned by the Hanko Authenticator. # FIDO UAF Client for Android Source: https://docs.hanko.io/hanko-authenticator/sdks/android Add on-device FIDO UAF authentication to your Android app. You can integrate FIDO-based strong multi-factor authentication into your existing Android app using the open source Hanko FIDO UAF Client. To learn more about integrating the client, view the documentation on [GitHub](https://github.com/teamhanko/fidouafclient) or get started with the [quickstart guide](/hanko-authenticator/quickstart/uaf-client). # FIDO UAF Client for iOS Source: https://docs.hanko.io/hanko-authenticator/sdks/ios Add on-device FIDO UAF authentication to your iOS app. You can integrate FIDO-based strong multi-factor authentication into your existing iOS app using the open source Hanko FIDO UAF Client. To learn more about integrating the client, view the documentation on [GitHub](https://github.com/teamhanko/fidouafclientios) or get started with the [quickstart guide](/hanko-authenticator/quickstart/uaf-client). # Hanko Keycloak plugin Source: https://docs.hanko.io/hanko-authenticator/sdks/keycloak-plugin Integrate the Hanko Authenticator into Keycloak as a login option. The Hanko Keycloak plugin allows you to integrate passwordless authentication into your existing infrastructure. With the plugin you can: * Let users log in with either their password or the Hanko Authenticator (FIDO UAF). * Use a customized account page to register and de-register a Hanko Authenticator. * Use RESTful API endpoints to allow registration and de-registration of a Hanko Authenticator. [View on GitHub](https://github.com/teamhanko/hanko-keycloak-plugin) for comprehensive documentation. # What is FIDO UAF? Source: https://docs.hanko.io/hanko-authenticator/what-is-fido-uaf Background reading on the FIDO Universal Authentication Framework (UAF) protocol that the Hanko Authenticator is built on. This page is optional background reading. If you just want to know what the Hanko Authenticator does for your app, see the [introduction](/hanko-authenticator/introduction) and [core components](/hanko-authenticator/core-components) instead. This page provides a high-level overview of the history and background of the FIDO Universal Authentication Framework (UAF) protocol — what's behind the acronym, the motivation behind it, and the core concepts and terminology it relies on. The Hanko Authenticator app and the Hanko FIDO UAF Client implement this protocol under the hood, but you don't need to understand it to integrate either one. ## The problem with passwords Authentication is fundamental to businesses for managing access to secured resources and services. Despite the growing expansion of technologies using biometric patterns for authentication, like iris scanners or fingerprint scanners, employing a username and password scheme still remains the most widespread method for doing authentication. Passwords are not without issues, however. According to the 2020 iteration of Verizon's often-cited [Data Breach Investigation Report](https://enterprise.verizon.com/resources/reports/2020-data-breach-investigations-report.pdf), phishing and the use of stolen credentials still rank among the top threat action varieties in data breaches, making up over 40% of the total. It also concludes that: > Hacking and even breaches in general \[...] are driven by credential theft. Over 80% of breaches within Hacking involve Brute force or the Use of lost or stolen credentials. Security issues of passwords also often interact with the fact that passwords turn out to be inconvenient for users. An ever-growing amount of cloud-based service offerings also potentially entails an ever-growing amount of passwords to remember, which often leads to credential reuse or the use of short, easy-to-remember passwords, making them susceptible to brute force attacks. With acknowledgement of the password problem and the rapid expansion of mobile devices and communication came solutions that envisioned the use of a second authentication step in order to provide stronger and more secure authentication. These developments resulted in the employment of One-Time-Passwords (OTPs) — short (typically 6 to 8 digit) codes that can be generated either directly on a mobile device through an app or generated on a separate remote device and sent to the user via Short-Messaging-Service (SMS). Although two-step authentication provides more security than password-only solutions, OTPs are still [vulnerable](https://krebsonsecurity.com/2018/08/reddit-breach-highlights-limits-of-sms-based-authentication/) to phishing and man-in-the-middle attacks. ## Enter the FIDO Alliance FIDO Alliance logo In 2012 PayPal, Lenovo, Nok Nok Labs, Validity Sensors, Infineon, and Agnitio founded the [FIDO Alliance](https://fidoalliance.org/), an open industry group whose primary goal was to eliminate passwords from the internet by developing an industry standard based on principles of public key cryptography, thus enabling authentication methods that are more secure and easier to use. In their own words, the Alliance's core missions are: 1. Ease of use 2. Privacy and security 3. Standardization ## FIDO UAF & FIDO U2F By 2014 the FIDO Alliance completed and published the first version of two of its major protocols: the [FIDO Universal Authentication Framework (FIDO UAF)](https://fidoalliance.org/specs/fido-uaf-v1.1-ps-20170202/fido-uaf-overview-v1.1-ps-20170202.html) and the [FIDO Universal 2nd Factor (FIDO U2F)](https://fidoalliance.org/specs/fido-uaf-v1.1-ps-20170202/fido-security-ref-v1.1-ps-20170202.html) protocol. FIDO U2F, developed by Google, Yubico, and NXP, was intended to serve as a protocol that facilitates augmenting existing password-based authentication schemes by also providing proof of possession of a separate physical hardware device (a security key) in addition to the password, using public key cryptography (digital signatures). Rather than typing a code (OTP), the user inserts a security key into their computer's USB port and taps it to verify their presence and complete the authentication process. FIDO UAF aimed at providing a generic framework for **passwordless** and **multi-factor** authentication, potentially leveraging the capabilities of a wide range of existing hardware devices (built-in or **bound** platform capabilities like fingerprint sensors, cameras, microphones, embedded TPM hardware) but also leaving open the possibility of using portable (also: **roaming**) devices not bound to any one specific device. This is the protocol underlying the **Hanko Authenticator** and the **Hanko FIDO UAF Client**. Both protocols' component architecture comprises: * a user side of the authentication process which includes: * A **FIDO client**: the software component processing UAF or U2F protocol messages on a user's device. The FIDO client acts as a mediating layer between an authenticator and a relying party, and can be a browser, a desktop application, a mobile application, or a platform (i.e. an operating system like Android or iOS). * An **authenticator**: the hardware device responsible for user verification and maintaining the cryptographic material. * a **relying party** side, i.e. the website or other entity that uses a FIDO protocol to authenticate users, which includes: * The relying party's (web) server hosting the application a user wants to authenticate with. * A **FIDO server**: the software component, typically deployed in the relying party's infrastructure, that meets UAF protocol server requirements. The FIDO UAF architecture also includes what is called an Authenticator Specific Module (ASM), which "is a software interface on top of UAF authenticators which gives a standardized way for FIDO UAF Clients to detect and access the functionality of UAF authenticators and hides internal communication complexity from FIDO UAF Client." ([Source](https://fidoalliance.org/specs/fido-uaf-v1.1-ps-20170202/fido-uaf-asm-api-v1.1-ps-20170202.html)) The following figure depicts a simplified overview of the key components of both protocol architectures. Architectural components of FIDO U2F and FIDO UAF ### Public key cryptography Both protocols rely on the use of public key cryptography for authentication, using hardware devices as so-called authenticators on the client side to generate cryptographic key pairs. The private key is stored securely on the user's device and never transmitted over a potentially insecure channel (i.e. the internet), while the public key is supplied to and stored by the relying party. Through the use of a **challenge-response** mechanism, relying parties issue challenges which a client must respond to by signing the challenge using the private key stored on the user's device. To do so, an end-user employs the biometric capabilities of their device (a face scan or a fingerprint) or — where unavailable — a PIN or a passphrase — to **locally** unlock access to the private key on their authenticator to create the digital signature. Biometric data (or PINs/passphrases) are also never transmitted over an insecure channel, making this procedure an inherently stronger and more secure method than using passwords. This is also where the term multi-factor comes into play. The three major authentication factors are: * Knowledge — something the entity knows; e.g., passwords or challenge-response techniques * Ownership — something the entity possesses; e.g., U2F tokens or ID cards * Inherence — something the entity is or is capable of; e.g., biometric properties or signatures The provision of biometric data (something you are) or a PIN (something you know) to unlock the private key on a device (something you have) ensures usage of at least two factors, thus lowering the overall chance of an unauthorized entity being able to provide both factors at once. ## FIDO core operations Authentication through FIDO protocols involves two major operations, sometimes also referred to as "protocol conversations" or "ceremonies": registration and authentication. ### Registration In the FIDO context, registration describes the process where a user registers a new account on a website/service, through which cryptographic key material is generated and associated with a relying party. Sequence diagram for the FIDO registration operation 1. The user visits the website of a relying party application through their web browser and initiates a sign-up process. 2. The client/web browser initiates a registration request with the relying party. 3. The relying party then issues a challenge for the authenticator to sign over. The interaction defines a parameter (RP, relying party) that denotes the origin of the challenge. Cryptographic credential material in FIDO is scoped in the sense that FIDO authenticators sign over an origin (usually the URL of the relying party application) with an associated private key. This so-called **token binding** ensures that the origin can't be spoofed through phishing. 4. The user is prompted to perform an authentication gesture. 5. Depending on the type of authenticator used, this gesture can either be the proof of **user presence** or a case of **user verification**. If the authenticator is a roaming authenticator, like a security key, the user simply confirms user presence, usually by tapping the authenticator device. If the authenticator is a mobile device or a platform device with built-in biometric capabilities, the user performs user verification by presenting a fingerprint or entering a PIN. 6. The result of the authentication gesture is then used to generate a **credential key pair** in the form of a private and a public key. 7. The credential private key is stored on the authenticator device. 8. The credential public key is sent to the relying party and signed with a private **attestation key**. This so-called **attestation** mechanism defines a process for authenticators to make verifiable claims to a relying party that the created credentials originate from a trusted authenticator. For this reason, authenticators possess another key pair, the **attestation key pair**, which is "burned" into the device during manufacturing. 9. The relying party can now verify that the attestation signature came from a genuine authenticator device. 10. The relying party then stores the credential public key to complete the registration process. ### Authentication In contrast to registration, authentication in the FIDO context describes the process of employing a FIDO authenticator to prove possession of a registered key to a relying party. Sequence diagram for the FIDO authentication operation 1. The user visits the website of a relying party application through their web browser and initiates a login process, providing a username or e-mail. 2. The client/web browser initiates an authentication request with the relying party. 3. As with registration, the relying party then issues a challenge for the authenticator to sign over. 4. The user is prompted to perform an authentication gesture. 5. The user performs the authentication gesture. 6. The result of the authentication gesture is used to unlock the **credential key pair**. 7. The relying party's challenge is signed with the credential private key. In contrast to registration, where a key pair is used to provide an **attestation** signature, the credential key pair is used to provide an **assertion** signature. 8. The resulting signature is sent to the relying party. 9. The relying party verifies the signature using the credential public key previously stored during registration. 10. The relying party then returns the verification result. ## Next steps Find out what the Hanko Authenticator adds to your application's MFA and login flows. Dive deeper by studying the official FIDO specifications. # Using Hanko with Permit.io Source: https://docs.hanko.io/integrations/permit This guide will show you how to add an easily manageable authorization layer on top of your Hanko implementation, providing you with a simple way to determine what users can access within the application after logging in. Although this application code is built with Next.js, Permit.io provides SDKs for any common language, So this example can give you a good idea of how it should look in your language. Note that this tutorial is meant to be used on an application with Hanko authentication already set up. We highly recommend cloning our [demo application](https://www.github.com/permitio/permit-hanko/) so you can follow the steps more easily. If you prefer to read the article without cloning the application, skip this section and continue to [Setup Basic Role Based Authorization](/integrations/permit#setup-basic-role-based-authorization). ## To clone the demo application, run the following commands: ```sh theme={null} git clone :permitio/permit-hanko.git ``` ```sh theme={null} npm install ``` ```sh theme={null} npm run dev ``` At this point, the application will fail to run as we need to set up the Hanko and Permit services. ## Setting up Hanko Passkey Authentication: Visit the Hanko webapp, create a new organization (Or use your existing one), and give it the name you want. In the main dashboard, create a new project - assign [http://localhost:3000](http://localhost:3000) as the App URL. From the Settings > General section of the project, copy the API URL. Paste the API URL to a new file called `.env.local`, in the root directory of the application. When we run the application again, we can see that the error is gone, and we can see the login page.Now, when we run the application again, we can see that the error is gone, and we can see the login page. To add this authentication window, use the Hanko SDK for JavaScript. You can see the element that implemented the login flow in the `app/auth/login/page.tsx` file. ```jsx theme={null} ``` We added the following middleware logic to the `middleware.ts` file that redirects the user to the login page if they are not authenticated: ```ts theme={null} const authenticateUser = async (req: NextRequest): Promise => { if (!hankoApiUrl) { return ""; } // Get Hanko token from cookie const hanko = req.cookies.get("hanko")?.value; ... // Authenticate user using Hanko const user = await authenticateUser(req); // Redirect to login page if user is not authenticated if (!user) { urlToRedirect.pathname = LOGIN_URL; return NextResponse.rewrite(urlToRedirect); } ``` With the authentication configuration and flow configured, we are ready to continue with the implementation of Permit.io for authorization in our application. ## Setup Basic Role Based Authorization With authentication done, it is time to set up our authorization layer. We'll start with setting up basic **role-based access control (RBAC)** to determine the actions our users can perform. In the [`/app/api/notes/route.ts`](https://github.com/permitio/permit-hanko/blob/main/src/app/api/notes/route.ts), you'll find four functions, `GET`, `POST`, `PUT`, and `DELETE` - responsible for the logic of getting, creating, updating, and deleting notes, respectively. If you look at the `route.ts` file, you will see that we are going to use a generic [`permit.check`](https://docs.permit.io/how-to/enforce-permissions/check/) [middleware.ts](https://github.com/permitio/permit-hanko/blob/main/src/middleware.ts) file. ```ts theme={null} const response = await fetch(`${pdpUrl}/allowed`, { method: "POST", headers: { Authorization: `Bearer ${permitApiKey}`, "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify({ user: user, action, resource: resource, context: {}, }), }); ``` This code is a generic `permit.check` function that checks the permissions configured for the application using three factors: **User** - the entity that attempts to perform the operation (in our case, a user authenticated with Hanko). **Action** - the operation that the user will attempt to perform (in our case, `GET`). **Resource** - the entity that the user will attempt to perform the operation on (in our case, the note). At this point, we haven't configured the Permit SDK key in the app, so any user can perform any operation. Setting up a Permit.io account will fix this. Now, we must configure these permissions in Permit.io. Note that we can adapt them to our needs without having to change any of the application code! Go to [app.permit.io](https://app.permit.io/), Create an account, set up a new organization, and give it whichever name you want. In the left sidebar, click on Policy, then go to the Roles tab, and create the following roles: Admin and User. create roles In the Resources tab, create a new resource called notes, with the following four actions and an owner attribute: `get`, `post`, `delete`, and `put`. create resources Back in the Policy tab, let's allow all users to get and `post` notes, and only admins to `put`, and `delete` notes. create resources To copy your API key, click your user profile in the top right of the screen, and click `Copy SDK API Key`. Add the key in your in the env.local file: ```sh theme={null} PERMIT_API_KEY= ``` We will also need to configure the Permit.io API endpoint to check the permissions. For this purpose, we will use the Permit cloud service. ```sh theme={null} PERMIT_PDP_URL=[https://cloudpdp.api.permit.io](https://cloudpdp.api.permit.io) ``` To make sure all environment variables are in place, restart the application. Now that we have everything set up within Permit.io, it is time to sign up with a user and test if it works. ## Sync Hanko Users to Permit.io To check the permissions we configured, we need to sync the users from Hanko to Permit.io, so our users will be known to the Permit policy engine. We will want to automatically assign a user role to every new user, so they will also be part of our newly configured policy. This role helps us to keep the principle of least privilege and give new users only very basic permissions in the application. In the demo application, you can find the following code in the `src/app/api/permit/route.ts` file: ```ts theme={null} const response = await permit.api.syncUser({ key, email, attributes: { roles: ["user"], }, }); await permit.api.roleAssignments.assign({ role: "user", tenant: "default", user: key, }); ``` This code, as you can see, syncs the user to Permit.io if they do not exist yet. ## Check the Permissions In the `localhost:3000` page, log in with a user of your choice, and make sure you have the right passkey configured. Create a new note on the first screen of the application. It should appear on the list. In the Permit.io Dashboard, go to the Audit Log tab in the left sidebar. You should see that the `post` action was logged. Clicking the log will allow you to see detailed information about the authorization decision that allowed for this action to be performed. `Allow` will equal `true` as this user has the User role. create resources If we try to delete the note, we will get an error message saying we are not allowed to access this resource. If we grant an Admin role to this user via Permit.io's UI, the error will be resolved and we will be able to delete the note. create resources Now that we are done with the Role Based model in our application let's go to the next phase and make our permissions more fine-grained ## Add Fine-Grained Attribute-Based Authorization For this section to run properly, you need to run the Permit.io PDP as a sidecar. [You can read how to do that here](https://docs.permit.io/how-to/deploy/deploy-to-production). As stated before, the delete action in our app is supposed to be limited to the same user who created the role. This is a more complex policy that cannot be defined by using simple roles - it needs attributes as well. We can configure this policy in Permit and see it take effect immediately in the application. Navigate to the Policy page, select ABAC Rules, and activate the ABAC option. Enable ABAC Go to the Resources tab and create a new Resource Set rule. This rule should validate if the user is the note's owner. Resource Set Return to the Policy tab and establish a policy allowing `put` and `delete` actions exclusively for the note's owner. Ensure the admin role retains all-action privileges. ABAC Policy Log out from the current user, register a new user, and verify that this new user cannot delete tasks. ABAC Audit Logs As the new user, create a note and confirm the ability to delete the newly created note. Log in with a different user after creating the note and attempt to delete it. This should fail, as the logged-in user is not the creator. ## Enforce Permissions Everywhere Sometimes, you will encounter a situation where you need to check permissions in the middle of the application logic. For example, you could want to restrict a particular operation to premium users only. Using Permit, the policy configuration always remains the same, and you'll only have to use the `permit.check` function in every place within the code to determine allowed/not allowed permissions. ```javascript theme={null} new Permit({token: }); permit.check(user, action, resource); ``` Using the `permit.check` function also lets you make decisions based on data that might not exist in the scope of the request in the middleware, so you get more granular decisions with no code changes. ## Add Fine-Grained Relationship Based Authorization Another approach for fine-grained authorization that we can use is Relationship-Based Access Control (ReBAC). Assuming a note app, we might want to create workspaces, organizations, and folders for our notes. In this case, we might do not have a dedicated owner field in the note entity, but we have a relationship between the note and the workspace. Permit also supports the configuration of ReBAC policies, we can easily implement it in our application without changing the `permit.check` or any enforcement code in the app. [Read more about modeling ReBAC here](https://docs.permit.io/modeling/google-drive). # Using Hanko with Supabase Source: https://docs.hanko.io/integrations/supabase This guide showcases how to add new user info, like user ID and email to the Supabase database, when users sign up with Hanko. Jump to [Nextjs guide](/quickstarts/fullstack/next) to learn how to add Hanko Auth in your Next App.
# Hanko Supabase Integration Guide **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Hanko authentication with Supabase database. You'll learn to automatically sync user data between Hanko and Supabase, creating user profiles and managing authentication state across both platforms. **Key Technologies**: * Hanko Elements (Authentication) * Supabase (Database & Backend) * Next.js (React Framework) * TypeScript * Supabase JavaScript Client * Database Schema Design **Prerequisites**: * Basic knowledge of React/Next.js * Understanding of database concepts * Node.js development environment * Active Hanko project configured * Supabase account and project **Tasks You'll Complete**: 1. Set up Supabase project and database 2. Create users table with proper schema 3. Configure Supabase client in your application 4. Build API endpoint for user synchronization 5. Integrate user sync with Hanko authentication 6. Test user creation and data flow
This guide uses Next.js, but you can apply the same concepts to other frameworks or languages. We're expanding our framework examples, so stay tuned for more! Sign up for a [Supabase](https://supabase.com/) account if you don't have one already. From the Supabase dashboard, click 'New Project' to create a project for your application. create new project In your project dashboard, navigate to 'Database' and create a new 'users' table. This table will store user information from Hanko. Add these columns beyond the default 'id': * 'user\_id' (to match Hanko's user ID) * 'email' (to store user email addresses) create new project In your project dashboard, go to 'Project Settings' > 'API'. Copy the 'URL' and 'service\_role' key, then add them to your `.env.local` file. ```sh .env.local theme={null} NEXT_PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io NEXT_PUBLIC_SUPABASE_PROJECT_URL=YOUR_SUPABASE_PROJECT_URL SUPABASE_SERVICE_ROLE_KEY=YOUR_SUPABASE_SERVICE_ROLE_KEY ``` Add the Supabase client library to your application (assuming Hanko Auth is already configured). ```bash npm theme={null} npm install @supabase/supabase-js ``` ```bash pnpm theme={null} pnpm add @supabase/supabase-js ``` ```bash yarn theme={null} yarn add @supabase/supabase-js ``` ```ts lib/supabase.ts theme={null} import { createClient } from "@supabase/supabase-js"; export const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_PROJECT_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY! ); ``` Build an API endpoint to sync user data between Hanko and Supabase. ```ts app/api/create-user/route.ts theme={null} import { NextResponse } from "next/server"; import { supabase } from "@/lib/supabase"; export async function POST(req: Request, res: Response) { try { const user = await req.json(); if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } let supauser; try { const { data, error } = await supabase .from("users") .select("*") .eq("user_id", user.id) .single(); if (error) { console.error(error); } supauser = data; if (!supauser) { const { data, error } = await supabase .from("users") .insert([{ user_id: user.id, email: user.email }]); if (error) { console.error(error); } supauser = data; } } catch (error) { console.error(error); } const user_data = { ...user, id: supauser?.id, }; return new NextResponse(JSON.stringify(user_data), { status: 200 }); } catch (error) { console.error("[CREATEUSER_ERROR]", error); return new NextResponse("Internal Error", { status: 500 }); } } ``` Modify your Hanko authentication component to automatically sync user data when `onSessionCreated` triggers. ```tsx components/hanko/HankoAuth.tsx theme={null} "use client"; import { useEffect, useCallback, useState } from "react"; import { useRouter } from "next/navigation"; import { register, Hanko } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ''; export default function HankoAuth() { const router = useRouter(); const [hanko, setHanko] = useState(); useEffect(() => setHanko(new Hanko(hankoApi)), []); const redirectAfterLogin = useCallback(() => { // successfully logged in, redirect to a page in your application router.replace("/dashboard"); }, [router]); useEffect( () => hanko?.onSessionCreated(async () => { const user = await hanko.user.getCurrent() const fetchData = async () => { if (!user) { console.error('No user data') return } try { const response = await fetch('/api/create-user', { method: 'POST', body: JSON.stringify(user), }) if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`) } catch (error) { console.error('Fetch Error: ', error) } } await fetchData() redirectAfterLogin(); }), [hanko, redirectAfterLogin] ); useEffect(() => { register(hankoApi).catch((error) => { console.error(error); }); }, []); return ; } ``` } > Full source code available on our GitHub # Welcome to the Hanko documentation Source: https://docs.hanko.io/introduction Learn how to integrate Hanko to securely and seamlessly onboard and authenticate your users. ## What is Hanko? Hanko is a fully open-source authentication and user management system built around a flexible API. It supports multiple authentication methods, including passwords, passkeys, two-factor authentication (2FA), single sign-on (SSO), and Hanko Elements — a set of lightweight, framework-agnostic web components for fast integration into any website or application. Hanko follows a privacy-first approach, focusing on data minimalism and phishing-resistant authentication methods such as passkeys. You retain full control over your data and can move seamlessly between self-hosted deployments and Hanko Cloud at any time. Hero Light Hero Light Please note that Hanko is a complete authentication solution. If you only want to add passkeys to your existing user base, check out [Passkey API](/passkey-api/introduction). ## Hanko quickstart guides Integrate Hanko using a quickstart guide for your favorite frameworks: } href="/quickstarts/fullstack/next" > Add authentication to your Next app quickly and easily with Hanko. } href="/quickstarts/frontend/react" > Make your react application secure by adding Hanko authentication. } href="/quickstarts/fullstack/nuxt" > Get started with adding secure and hassle-free authentication to your Nuxt app. } href="/quickstarts/frontend/svelte" > Add Hanko authentication to your Svelte app. [Discover all guides >>](/quickstarts/overview) # Client-first login flow Source: https://docs.hanko.io/passkey-api/client-first-login-flow Learn how to start the login flow from your frontend. While you can't skip hitting your backend completely, you can change up the flow a little. When logging in, instead of going frontend → backend → Passkey API, you can let the frontend talk to the Passkey API directly. The `/login/initialize` and `/login/finalize` endpoints **do not require you to send the secret API key.** When using the Passkey API, after calling the `/login/finalize` endpoint as shown above, you will receive a JSON Web Token (JWT) in the response. This JWT contains the `user_id` and `username` that your backend sent back when the passkey was registered. To verify that the JWT was issued by the Passkey API, you can use the JWKS\* located at `/{tenant_id}/.well-known/jwks.json`. The JWKS contains the public keys used for signing the JWTs. **\*** JWKS are a set of keys (random strings) that are intended to let you verify where a JWT comes from. For example, with the JWKS at `/AcmeCorp/.well-known/jwks.json`, you can check whether a JWT was issued by AcmeCorp or not. (There are libraries in most languages that help you do this!) Once you have verified the JWT on your backend, you can exchange it for a session. This way, your backend doesn't come into play until the user has successfully authenticated with a passkey. # Example implementation Source: https://docs.hanko.io/passkey-api/example-implementation Learn how to utilize the Passkey API using raw HTTP requests without any SDK. This is an example implementation showing how to use the Passkey API with Node.js and Flask. (We'll be adding more languages and frameworks soon.) However, if you're already using JavaScript/TypeScript for your backend, you can use [@teamhanko/passkeys-sdk](https://www.npmjs.com/package/@teamhanko/passkeys-sdk), which handles all of the below for you. Otherwise, please make sure to always send JSON with `Content-Type: application/json`. As of writing, for the frontend, the Web Authentication API expects you to pass `ArrayBuffer` (instead of plain old objects) in a lot of places, which can be inconvenient. In the examples below, we use [@github/webauthn-json](https://github.com/github/webauthn-json#githubwebauthn-json), which is a wrapper for the Web Authentication API to make things easier. *** Get your tenant ID and API key from your [Hanko Cloud](https://cloud.hanko.io) project dashboard. The base URL for the Passkey API depends on your `tenant_id`. ```sh .env theme={null} PASSKEY_TENANT_ID=your-tenant-id PASSKEY_SECRET_API_KEY=your-secret-api-key ``` If the app you’re building supports organizations, teams, or anything similar, you will likely have heard of multitenancy. The Passkey API supports multitenancy as well — you can create tenants (a.k.a. organizations, teams, …) and add the passkeys of users exclusively to those tenants. Then your users will only be able to log in with passkeys specifically for that tenant. For example: In your app, a user is part of two teams: the “ACME Corp.” and the “A-Team.” They create a passkey to log into “ACME Corp.” That passkey will only work for the “ACME Corp.”, not the “A-Team”. If you self-host the Passkey API, there are endpoints that let you create, list, and manage tenants programmatically. [See the API reference](https://github.com/teamhanko/passkey-server/tree/main/spec). Registering passkeys is a two-step process. First, let's add an endpoint to our backend. **Backend** ```jsx theme={null} const tenantId = process.env.PASSKEY_TENANT_ID; if (!tenantId) throw new Error("Missing PASSKEY_TENANT_ID"); const apiKey = process.env.PASSKEY_SECRET_API_KEY; if (!apiKey) throw new Error("Missing PASSKEY_SECRET_API_KEY"); const baseUrl = `https://passkeys.hanko.io/${tenantId}`; const headers = { apiKey, "Content-Type": "application/json" }; app.post("/passkey/start-registration", async (req, res) => { // Remember: to register a passkey, the user needs to be logged in first. // Once the passkey is added to the user's account, they can // use it to log in. // This is the currently logged in user: const user = req.session.user; // Send the id and name of the user stored in our DB. // (both fields are required) const creationOptions = await fetch(baseUrl + "/registration/initialize", { method: "POST", headers, body: JSON.stringify({ user_id: user.id.toString(), // Must be a string! username: user.username, }), }).then((res) => res.json()); // creationOptions is an object that can directly be passed to create() // (the function that opens the "create passkey" dialog) // in the frontend. res.json(creationOptions); }); app.post("/passkey/finalize-registration", async (req, res) => { const data = await fetch(baseUrl + "/registration/finalize", { method: "POST", headers, body: JSON.stringify(req.body), // Forward newly created credential }).then((res) => res.json()); // The response from the Passkey API contains a JWT (`data.token`). // What you do with this JWT is up to you. // // // The JWT contains 4 claims: // "sub": the user_id we used for "/registration/initialize". // you can use this to issue a session for the user, for example // // "cred": the credential_id (ID of the passkey the user chose) // // "aud": an array with a single string. // the string is the ID of the relying party (your app). // e.g. ["example.com"] // // "iat": the expiration date (very short) // // // Here, we don't need to do anything with it, since the user already // is logged in. In the login endpoints, later in this guide, we'll // use the data contained in the JWT to create a session for our user. res.redirect("/success"); }); ``` ```python theme={null} tenant_id = os.getenv("PASSKEY_TENANT_ID") api_key = os.getenv("PASSKEY_API_KEY") baseUrl = f"https://passkeys.hanko.io/{tenant_id}" headers = { "apikey": api_key, "Content-Type": "application/json", } @app.route('/passkey/start-registration', methods=["POST"]) def start_registration(): print("registering passkey") if 'user_id' not in session: return jsonify({"error": "User must be logged in to register a passkey"}), 401 user_id = session['user_id'] user_email = session['email'] payload = { "user_id": user_id, "username": user_email, } response = requests.post(f"{baseUrl}/registration/initialize", headers=headers, json=payload) creationOptions = response.json() return jsonify(creationOptions) @app.route("/passkey/finalize-registration", methods=["POST"]) def finalize_registration(): data = request.json response = requests.post(f"{baseUrl}/registration/finalize", headers=headers, json=data) data = response.json() return jsonify({"message": "Passkey registered successfully"}), 200 ``` **Frontend** ```jsx theme={null} import { create, get } from "@github/webauthn-json"; async function registerPasskey() { // Let's send a request to our backend to start the registration process. // The response JSON can directly be passed to create(...) below. const creationOptions = await fetch("/passkey/start-registration", { method: "POST", }).then((res) => res.json()); // Open "create passkey" dialog const credential = await create(creationOptions); // User successfully created a passkey on their device. // // The resulting `credential` object needs to be sent back to the // Passkey API as-is, through our backend: // // frontend → backend → passkey API return fetch("/passkey/finalize-registration", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(credential), }); } ``` Here's what the whole flow looks like As you can see, there are two steps here ("start" and "finalize"), which pass through the frontend, backend, and Passkey API. The process looks very similar for logging in — it's also a two-step process where your frontend, backend, and the Passkey API are involved. Similar to how registering a passkey is a two-step process, so is logging in. **Backend:** ```jsx theme={null} app.post("/passkey/start-login", async (req, res) => { const loginOptions = await fetch(baseUrl + "/login/initialize", { method: "POST", headers, }).then((res) => res.json()); // loginOptions is an object that can directly be passed to get() // (the function that opens the "select passkey" dialog) // in the frontend. res.json(loginOptions); }); app.post("/passkey/finalize-login", async (req, res) => { const data = await fetch(baseUrl + "/login/finalize", { method: "POST", headers, body: JSON.stringify(req.body), // Credential the user selected }).then((res) => res.json()); // Like when registering, data.token is a JWT that contains claims // about the user (see above) res.redirect("/success"); }); ``` ```python theme={null} @app.route("/passkey/start-login", methods=["POST"]) def start_login(): response = requests.post(f"{baseUrl}/login/initialize", headers=headers) login_options = response.json() return jsonify(login_options) @app.route("/passkey/finalize-login", methods=["POST"]) def finalize_login(): client_data = request.json response = requests.post(f"{baseUrl}/login/finalize", headers=headers, json=client_data) data = response.json() # Now you can use the data from the JWT to create a session for the user token = data.get('token') decoded_payload = jwt.decode(token, options={"verify_signature": False}) user_id = decoded_payload.get('sub') user = next((user for user in users if user['id'] == user_id), None) if user: session["user_id"] = user["id"] session["email"] = user["email"] user_info = {"id": user["id"], "email": user["email"]} return jsonify({"message": "Login successful", "user": user_info}), 200 else: return jsonify({"message": "Invalid credentials"}), 401 ``` **Frontend** ```jsx theme={null} async function loginWithPasskey() { const loginOptions = await fetch("/passkey/start-login", { method: "POST", }).then((res) => res.json()); // Open "select passkey" dialog const credential = await get(loginOptions); // User selected a passkey to use. // // The returned `credential` object needs to be sent back to the // Passkey API as-is. return fetch("/passkey/finalize-login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(credential), }); } ``` For logging in, the server can also talk to the Passkey API directly, instead of going through your backend first. Whether you go with the server-first or client-first approach is up to preference. See [Client-First Login Flow](/passkey-api/client-first-login-flow). # Example payment transaction Source: https://docs.hanko.io/passkey-api/example-transaction Learn how to use passkeys to secure a payment transaction. In the last section you learned how to use the Passkey API in a vanilla js way without any SDK. This example shows you how to use the Passkey API to secure payment transactions. If you skipped the last section, we recommend you to read it as we will referring to settings and variables. Be aware that all transaction API endpoints are secured with your API key. *** ## Add endpoints to start a transaction Every transaction requires a user ID, a transaction ID and the transaction data to be performed. Be aware that a transaction ID needs to be a tenant-wide unique identifier. Using the same identifier with the same or another user on the same tenant will lead to a `409 Conflict` http status message. **Backend:** ```jsx theme={null} app.post("/passkey/start-transaction", async (req, res) => { // Remember: to start a transaction, the user needs to be logged in first AND have a registered passkey. // This is the currently logged-in user: const user = req.session.user; /* The transaction body can look like this: { transactionId: "your-unique-transaction-identifier", transactionData: { amount: 123.45, usedFor: "Buying a Hanko Cloud membership" ... } } */ const transactionBody = req.body; const transactionOptions = await fetch(baseUrl + "/transaction/initialize", { method: "POST", headers, body: JSON.stringify({ user_id: user.id.toString(), // must be a string! transaction_id: transactionBody.transactionId, transaction_data: transactionBody.transactionData, }), }).then((res) => res.json()); // transactionOptions is an object that can directly be passed to get() // (the function that opens the "select passkey" dialog) // in the frontend. res.json(transactionOptions); }); app.post("/passkey/finalize-transaction", async (req, res) => { const data = await fetch(baseUrl + "/transaction/finalize", { method: "POST", headers, body: JSON.stringify(req.body), // Credential the user selected }).then((res) => res.json()); // Additional to the user claims the JWT contains a trans-claim which contains the transaction_id res.redirect("/success"); }); ``` **Frontend:** ```jsx theme={null} async function transactionWithPasskey(amount, usedFor) { const transactionOptions = await fetch("/passkey/start-transaction", { method: "POST", body: JSON.stringify({ transactionId: "unique-transaction-identifier", transactionData: { amount, usedFor, }, }), }).then((res) => res.json()); // Open "select passkey" dialog const credential = await get(transactionOptions); // User selected a passkey to use. // // The returned `credential` object needs to be sent back to the // Passkey API as-is. return fetch("/passkey/finalize-transaction", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(credential), }); } ``` # Introduction to Passkey API Source: https://docs.hanko.io/passkey-api/introduction Add passkey support to your existing auth system with Hanko Passkey API. Hanko Passkey API adds support for passkeys for **existing users** of your platform. It's designed to be used **together with your own auth system**, and can be used without any other Hanko product. Users cannot create an account through the Passkey API. Instead, the Passkey API enables your users to add passkeys to their existing account (they have to be logged in first) or to use them to secure payment transactions. Please note that the Passkey API is **not** a full authentication solution — it's only intended to be used together with another authentication system that doesn't support passkeys natively. If you need a complete, open source authentication solution, check out [Hanko](/introduction). The Passkey API is designed to be used both from your backend and frontend: * Some requests (e.g. logging in) can be made to the Passkey API directly from the frontend. These do not require a secret API key. * All other requests that require a secret API key (e.g. registering a new passkey) should only be made from your backend. You should **never** leak that secret API key to the client. ## Next steps } href="/passkey-api/setup-passkey-project" > Set up a Passkey API project on Hanko Cloud. } href="/passkey-api/example-implementation" > A Node.js example showcasing implementation of the Passkey API without any SDK. } href="/passkey-api/js-sdk" > If you’re already using JS/TS for your backend, you can use our SDK to easily integrate the Passkey API. } href="/passkey-api/next-auth" > If you're using NextAuth for handling auth in your Next.js app, you can use our provider to easily add passkey support. # JavaScript/TypeScript SDK Source: https://docs.hanko.io/passkey-api/js-sdk A lean, type-safe, `fetch`-based API client for the Hanko Passkey API The `@teamhanko/passkeys-sdk` package lets you call the Hanko Passkey API from JavaScript/TypeScript that supports `fetch`. This includes Node.js, Browsers, Deno, Bun, and frameworks like Next.js, Astro, and SvelteKit. ```bash npm theme={null} npm i @teamhanko/passkeys-sdk ``` ```bash yarn theme={null} yarn add @teamhanko/passkeys-sdk ``` ```bash bun theme={null} bun add @teamhanko/passkeys-sdk ``` ```bash pnpm theme={null} pnpm add @teamhanko/passkeys-sdk ``` ## Usage A `tenant` is an API client instance for one tenant of the Hanko Passkey API. If the app you’re building supports organizations, teams, or anything similar, you will likely have heard of multitenancy. The Passkey API supports multitenancy as well — you can create tenants (a.k.a. organizations, teams, …) and add the passkeys of users exclusively to those tenants. Then your users will only be able to log in with passkeys specifically for that tenant. For example: In your app, a user is part of two teams: the “ACME Corp.” and the “A-Team.” They create a passkey to log into “ACME Corp.” That passkey will only work for the “ACME Corp.”, not the “A-Team”. If you use Hanko Cloud, get your tenant ID and API key from the [dashboard](https://cloud.hanko.io/organizations). Create a new tenant instance: ```ts theme={null} const passkeyApi = tenant({ tenantId: "", apiKey: "", }); ``` * If you only use public API methods, like `/login/initialize`, you can omit the `apiKey`. * If you're self-hosting the Passkey API, make sure to pass the `baseUrl` as well. Now you're ready to call the API. For example, to start the process of registering a new passkey: ```ts theme={null} const creationOptions = await tenant.registration.initialize({ userId: "", username: "", }); ``` ## Example Implementation ```bash npm theme={null} npm i @teamhanko/passkeys-sdk ``` ```bash yarn theme={null} yarn add @teamhanko/passkeys-sdk ``` ```bash bun theme={null} bun add @teamhanko/passkeys-sdk ``` ```bash pnpm theme={null} pnpm add @teamhanko/passkeys-sdk ``` Get your tenant ID and API key from [Hanko Cloud](https://cloud.hanko.io/) and add them to your `.env` file. ```bash .env theme={null} PASSKEYS_API_KEY=your-api-key PASSKEYS_TENANT_ID=your-tenant-id ``` On your backend, you’ll have to call `tenant({ ... }).registration.initialize()` and `registration.finalize()` to create and store a passkey. ```js services.js theme={null} import { tenant } from "@teamhanko/passkeys-sdk"; import dotenv from "dotenv"; import db from "../db.js"; dotenv.config(); const passkeyApi = tenant({ apiKey: process.env.PASSKEYS_API_KEY, tenantId: process.env.PASSKEYS_TENANT_ID, }); async function startServerPasskeyRegistration(userID) { const user = db.users.find((user) => user.id === userID); const createOptions = await passkeyApi.registration.initialize({ userId: user.id, username: user.email || "", }); return createOptions; } async function finishServerPasskeyRegistration(credential) { await passkeyApi.registration.finalize(credential); } ``` ```js controllers.js theme={null} async function handlePasskeyRegister(req, res) { const { user } = req; const userID = user.id; if (!userID) { return res.status(401).json({ message: "Unauthorized" }); } console.log("userId", userID); const { start, finish, credential } = req.body; try { if (start) { const createOptions = await startServerPasskeyRegistration(userID); console.log("registration start"); return res.json({ createOptions }); } if (finish) { await finishServerPasskeyRegistration(credential); return res.json({ message: "Registered Passkey" }); } } catch (error) { return res.status(500).json(error); } } ``` **Frontend** On your frontend, the `registerPasskey()` function handles the passkey registration process. It first sends a request to the server to initiate the registration process and receives the response for creating a new passkey. It then uses the `@github/webauthn-json` library to create a new passkey credential based on the received options from the response. Finally, it sends another request to the server with the newly created credential to complete the registration process. ```tsx theme={null} async function registerPasskey() { const createOptionsResponse = await fetch("http://localhost:5001/api/passkeys/register", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: 'include', body: JSON.stringify({ start: true, finish: false, credential: null }), }); const { createOptions } = await createOptionsResponse.json(); console.log("createOptions", createOptions) const credential = await create( createOptions as CredentialCreationOptionsJSON, ); console.log(credential) const response = await fetch("http://localhost:5001/api/passkeys/register", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ start: false, finish: true, credential }), }); console.log(response) if (response.ok) { toast.success("Registered passkey successfully!"); return; } } ``` ```js services.js theme={null} async function startServerPasskeyLogin() { const options = await passkeyApi.login.initialize(); return options; } async function finishServerPasskeyLogin(options) { const response = await passkeyApi.login.finalize(options); return response; } ``` ```js controllers.js theme={null} async function handlePasskeyLogin(req, res) { const { start, finish, options } = req.body; try { if (start) { const loginOptions = await startServerPasskeyLogin(); return res.json({ loginOptions }); } if (finish) { const jwtToken = await finishServerPasskeyLogin(options); const userID = await getUserID(jwtToken?.token ?? ""); console.log("userID from hanko", userID); const user = db.users.find((user) => user.id === userID); if (!user) { return res.status(401).json({ message: "Invalid user" }); } console.log("user", user); const sessionId = uuidv4(); setUser(sessionId, user); res.cookie("sessionId", sessionId); return res.json({ message: " Passkey Login successful" }); } } catch (error) { console.error(error); return res .status(500) .json({ message: "An error occurred during the passke login process." }); } } ``` **Frontend** ```tsx theme={null} async function signInWithPasskey() { const createOptionsResponse = await fetch("http://localhost:5001/api/passkeys/login", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: 'include', body: JSON.stringify({ start: true, finish: false, credential: null }), }); const { loginOptions } = await createOptionsResponse.json(); // Open "register passkey" dialog const options = await get( loginOptions as any, ); const response = await fetch("http://localhost:5001/api/passkeys/login", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: 'include', body: JSON.stringify({ start: false, finish: true, options }), }); if (response.ok) { console.log("user logged in with passkey") navigate("/dashboard") return; } } ``` ## Try it yourself Check out sample apps made using the SDK: } > Full source code available on our GitHub. } > Full source code available on our GitHub. # Passkey MFA Source: https://docs.hanko.io/passkey-api/mfa Learn how to implement multi-factor authentication (MFA) with Passkey using Passkey SDK. Passkey MFA is a multi-factor authentication (MFA) method that enhances account security by adding passkeys as a second factor to traditional password-based logins. It ensures that only users with access to both the password and the registered device can successfully authenticate, providing an extra layer of protection against unauthorized access. This example demonstrates how to implement MFA in Node.js using the [@teamhanko/passkeys-sdk](https://www.npmjs.com/package/@teamhanko/passkeys-sdk). If you're not using a JS/TS backend, you can achieve the same result by utilizing the [Passkey API](/passkey-api/reference/credentials/start-mfa-login) directly. This guide showcases how to add passkeys as second factor for password-based logins. If your goal is to set up a passkey-based passwordless login system instead, please refer to [this guide](/passkey-api/example-implementation) and the [Passkey API documentation](/passkey-api/reference/credentials/start-passkey-registration) for more suitable instructions. ## Install Passkey SDK Install the Passkey SDK: ```bash npm theme={null} npm i @teamhanko/passkeys-sdk ``` ```bash yarn theme={null} yarn add @teamhanko/passkeys-sdk ``` ```bash bun theme={null} bun add @teamhanko/passkeys-sdk ``` ```bash pnpm theme={null} pnpm add @teamhanko/passkeys-sdk ``` ## Get your tenant ID and API key Get your tenant ID and API key from Hanko Cloud and add them to your `.env` file. ```bash .env theme={null} PASSKEYS_API_KEY=your-api-key PASSKEYS_TENANT_ID=your-tenant-id ``` ## Allow users to register passkeys for MFA On your backend, you’ll have to call `tenant({ ... }).user(userId).mfa.registration.initialize()` and `mfa.registration.finalize()` to create and store a passkey for your user which will be used as an MFA. ```js services.js theme={null} import { tenant } from "@teamhanko/passkeys-sdk"; import dotenv from "dotenv"; import db from "../db.js"; dotenv.config(); const passkeyApi = tenant({ apiKey: process.env.PASSKEYS_API_KEY, tenantId: process.env.PASSKEYS_TENANT_ID, }); async function startMfaRegistration(userID) { const user = db.users.find((user) => user.id === userID); const createOptions = await passkeyApi .user(user.id) .mfa.registration.initialize({ username: user.email || "", }); return createOptions; } async function finishMfaRegistration(userID, credential) { const user = db.users.find((user) => user.id === userID); await passkeyApi.user(user.id).mfa.registration.finalize(credential); } ``` ```js controllers.js theme={null} async function handleMfaRegister(req, res) { const { user } = req; const userID = user.id; if (!userID) { return res.status(401).json({ message: "Unauthorized" }); } const { start, finish, credential } = req.body; try { if (start) { const createOptions = await startMfaRegistration(userID); return res.json({ createOptions }); } if (finish) { await finishMfaRegistration(userID, credential); const user = db.users.find((user) => user.id === userID); user.mfaEnabled = true; return res.json({ message: "Registered MFA" }); } } catch (error) { return res.status(500).json(error); } } ``` ### Frontend On your frontend, the `registerMfaPasskey()` function handles the passkey registration process. It first sends a request to the server to initiate the registration process and receives the response for creating a new passkey. It then uses the `@github/webauthn-json` library to create a new passkey credential based on the received options from the response. Finally, it sends another request to the server with the newly created credential to complete the registration process. ```tsx theme={null} async function registerMfaPasskey() { const createOptionsResponse = await fetch( "http://localhost:5001/api/passkeys/mfa/register", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ start: true, finish: false, credential: null }), } ); const { createOptions } = await createOptionsResponse.json(); console.log("createOptions", createOptions); const credential = await create( createOptions as CredentialCreationOptionsJSON ); console.log(credential); const response = await fetch( "http://localhost:5001/api/passkeys/mfa/register", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ start: false, finish: true, credential }), } ); console.log(response); if (response.ok) { toast.success("Registered MFA passkey successfully!"); return; } } ``` ## Authenticate users with MFA ```js services.js theme={null} async function startMfaLogin(userID) { const user = db.users.find((user) => user.id === userID); const options = await passkeyApi.user(user.id).mfa.login.initialize(); return options; } async function finishMfaLogin(userID, options) { const user = db.users.find((user) => user.id === userID); const response = await passkeyApi.user(user.id).mfa.login.finalize(options); return response; } ``` ```js controllers.js theme={null} async function handleMfaLogin(req, res) { const { user } = req; const userID = user.id; if (!userID) { return res.status(401).json({ message: "MFA Login not allowed" }); } const { start, finish, options } = req.body; try { if (start) { const loginOptions = await startMfaLogin(userID); return res.json({ loginOptions }); } if (finish) { const jwtToken = await finishMfaLogin(userID, options); const newUserID = await getUserID(jwtToken?.token ?? ""); const user = db.users.find((user) => user.id === newUserID); if (!user) { return res.status(401).json({ message: "Invalid user" }); } const sessionId = uuidv4(); setUser(sessionId, user); return res.json({ message: " MFA Passkey Login successful" }); } } catch (error) { console.error(error); return res .status(500) .json({ message: "An error occurred during the passkey login process." }); } } ``` ### Frontend Feel free to customize the MFA flow based on your app's requirements. In our [example implementation](https://github.com/teamhanko/passkeys-react-express), if `mfaRequired=true` is received from the login API, the user is redirected to an MFA page where passkey-based multi-factor authentication is performed. ```tsx theme={null} async function mfaLogin() { const createOptionsResponse = await fetch( "http://localhost:5001/api/passkeys/mfa/login", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ start: true, finish: false, credential: null }), } ); const { loginOptions } = await createOptionsResponse.json(); // Open "register passkey" dialog const options = await get(loginOptions as any); const response = await fetch("http://localhost:5001/api/passkeys/mfa/login", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ start: false, finish: true, options }), }); if (response.ok) { console.log("user logged in with mfa passkey"); navigate("/dashboard"); return; } } ``` ## Try it yourself } > Full source code available on our GitHub # Next.js with NextAuth (now known as Auth.js) Source: https://docs.hanko.io/passkey-api/next-auth Learn how to add passkeys to your Next.js app which already uses Auth.js for authentication. Once you’ve initialized your Next app with [NextAuth](https://authjs.dev/reference/nextjs), install passkey provider and the [webauthn-json](https://github.com/github/webauthn-json) package. ```bash npm theme={null} npm i @teamhanko/passkeys-next-auth-provider @github/webauthn-json ``` ```bash pnpm theme={null} pnpm add @teamhanko/passkeys-next-auth-provider @github/webauthn-json ``` ```bash bun theme={null} bun add @teamhanko/passkeys-next-auth-provider @github/webauthn-json ``` ```bash yarn theme={null} yarn add @teamhanko/passkeys-next-auth-provider @github/webauthn-json ``` Get your tenant ID and API key from [Hanko Cloud](https://cloud.hanko.io/organizations) and add them to your `.env.local` file. ```sh .env.local theme={null} PASSKEYS_API_KEY=your-api-key NEXT_PUBLIC_PASSKEYS_TENANT_ID=your-tenant-id ``` If you're self-hosting: 1. make sure to pass the `baseUrl` to both `tenant` (in `[...nextauth].ts`) and `signInWithPasskey()` (in your component). 2. get your tenant ID via the admin API ```ts app/api/auth/[...nextauth]/route.ts theme={null} import { tenant, PasskeyProvider, } from "@teamhanko/passkeys-next-auth-provider"; export default NextAuth({ providers: [ PasskeyProvider({ tenant: tenant({ apiKey: process.env.PASSKEYS_API_KEY, tenantId: process.env.NEXT_PUBLIC_PASSKEYS_TENANT_ID, }), async authorize({ userId }) { const user = db.users.find(userId); // Do more stuff return { id: user.id, name: user.username, }; }, }), ], }); ``` Your users will have to add passkeys to their account somehow. It's up to you how and where you let them do this, but typically this would be a button on an "Account Settings" page. On your backend, you'll have to call `tenant({ ... }).registration.initialize()` and `.registration.finalize()` to create and store a passkey for your user. On your frontend, you'll have to call `create()` from `@github/webauthn-json` with the object `.registration.initialize()` returned. `create()` will return a `PublicKeyCredential` object, which you'll have to pass to `.registration.finalize()`. **Backend:** ```ts lib/passkey-registration.ts theme={null} "use server"; // This is *your* server-side code; you need to implement this yourself. // NextAuth takes care of logging in the user after they have registered their passkey. import { authOptions } from "./app/api/auth/[...nextauth]/route.ts"; // Only required because of a NextAuth limitation import { getServerSession } from "next-auth"; import { tenant } from "@teamhanko/passkeys-next-auth-provider"; const passkeyApi = tenant({ apiKey: process.env.PASSKEYS_API_KEY, tenantId: process.env.NEXT_PUBLIC_PASSKEYS_TENANT_ID, }); export async function startServerPasskeyRegistration() { const session = await getServerSession(authOptions); if (!session?.user?.id) throw new Error("Not logged in"); const createOptions = await passkeyApi.registration.initialize({ userId: session.user.id, username: session.user.name, }); return createOptions; } export async function finishServerPasskeyRegistration(credential: any) { const session = await getServerSession(authOptions); if (!session) throw new Error("Not logged in"); await passkeyApi.registration.finalize(credential); // Now the user has registered their passkey and can use it to log in. // You don't have to do anything else here. } ``` **Frontend:** ```jsx components/PasskeyRegistrationButton.tsx theme={null} // This is your client-side code. NextAuth takes care of logging in the user after they have registered their passkey using registerPasskey function. "use client" import { finishServerPasskeyRegistration, startServerPasskeyRegistration, } from "@/lib/passkey-registration"; import { create } from "@github/webauthn-json"; export default function RegisterNewPasskey() { async function registerPasskey() { const createOptions = await startServerPasskeyRegistration(); // Open "register passkey" dialog const credential = await create(createOptions as any); await finishServerPasskeyRegistration(credential); // Now the user has registered their passkey and can use it to log in. } return ( ); } ``` Let's add a button that triggers the "Sign in with passkey" dialog: ```jsx components/PasskeyLoginButton.tsx theme={null} "use client"; import { signInWithPasskey } from "@teamhanko/passkeys-next-auth-provider/client"; export default function LoginButton() { return ( ); } ``` If you don't want to add a button just for passkeys, you can add autofill support to your username (or email) fields: Clicking on any passkey in the autofill popup will immediately log the user in, going through the same flow as if they had clicked the "Sign in with passkey" button earlier in this guide. To add autofill support: * add `autoComplete="username webauthn"` to your username field * call `signInWithPasskey.conditional()` when the login form loads **Example:** ```jsx theme={null} "use client"; import { signInWithPasskey } from "@teamhanko/passkeys-next-auth-provider/client"; export default function LoginForm() { // Call signInWithPasskey.conditional() once, when LoginForm mounts. // // .conditional() returns a cleanup function. // Please make sure to return it from useEffect: useEffect(() => { return signInWithPasskey.conditional({ tenantId: process.env.NEXT_PUBLIC_PASSKEYS_TENANT_ID, }); }, []); return (
{/* Add "webauthn" to input autoComplete: */}
); } ```
} > Full source code available on our GitHub
# Finish MFA Login Source: https://docs.hanko.io/passkey-api/reference/credentials/finish-mfa-login openapi-passkeys post /{tenant_id}/mfa/login/finalize Finalize the login operation # Finish MFA Registration Source: https://docs.hanko.io/passkey-api/reference/credentials/finish-mfa-registration openapi-passkeys post /{tenant_id}/mfa/registration/finalize Finish credential registration process # Finish Passkey Registration Source: https://docs.hanko.io/passkey-api/reference/credentials/finish-passkey-registration openapi-passkeys post /{tenant_id}/registration/finalize Finish credential registration process # List Credentials Source: https://docs.hanko.io/passkey-api/reference/credentials/list-credentials openapi-passkeys get /{tenant_id}/credentials Get a list of webauthn credentials # Start MFA Login Source: https://docs.hanko.io/passkey-api/reference/credentials/start-mfa-login openapi-passkeys post /{tenant_id}/mfa/login/initialize Initialize a login flow for MFA # Start MFA Registration Source: https://docs.hanko.io/passkey-api/reference/credentials/start-mfa-registration openapi-passkeys post /{tenant_id}/mfa/registration/initialize Initialize a registration for mfa credentials # Start Passkey Registration Source: https://docs.hanko.io/passkey-api/reference/credentials/start-passkey-registration openapi-passkeys post /{tenant_id}/registration/initialize Initialize a registration for webauthn credentials # Update Credential Source: https://docs.hanko.io/passkey-api/reference/credentials/update-credential openapi-passkeys patch /{tenant_id}/credentials/{credential_id} Endpoint for updating a webauthn credential # Well-known JWKS Source: https://docs.hanko.io/passkey-api/reference/credentials/well-known-jwks openapi-passkeys get /{tenant_id}/.well-known/jwks.json Endpoint for fetching JWKS # Finalize transaction Source: https://docs.hanko.io/passkey-api/reference/finalize-transaction openapi-passkeys post /{tenant_id}/transaction/finalize Finalize a transaction # Finish Login Source: https://docs.hanko.io/passkey-api/reference/finish-login openapi-passkeys post /{tenant_id}/login/finalize Finalize the login operation # Initialize a transaction Source: https://docs.hanko.io/passkey-api/reference/initialize-a-transaction openapi-passkeys post /{tenant_id}/transaction/initialize Initializes a new transaction for an existing user # List audit log entries Source: https://docs.hanko.io/passkey-api/reference/list-audit-logs openapi-passkeys get /{tenant_id}/audit_logs Get a list of audit logs # Remove Credential Source: https://docs.hanko.io/passkey-api/reference/remove-credential openapi-passkeys delete /{tenant_id}/credentials/{credential_id} Endpoint for removing a webauthn credential # Start Login Source: https://docs.hanko.io/passkey-api/reference/start-login openapi-passkeys post /{tenant_id}/login/initialize Initialize a login flow for passkeys # Examples Source: https://docs.hanko.io/passkey-api/resources/examples Example apps showcasing integration of Hanko Passkey API with your favorite frameworks } > Sample app showing how to integrate Hanko Passkey API with Next.js and NextAuth. } > Sample app showing how to integrate Hanko Passkey API with Next.js. } > Sample app showing how to integrate Hanko Passkey API with Remix. } > Sample app showing how to integrate Hanko Passkey API with T3 Stack. } > Sample app showing how to integrate Hanko Passkey API with Express and React. } > Sample app showing how to integrate Hanko Passkey API with Vue and Express. } > Sample app showing how to integrate Hanko Passkey API with Flask backend. # Tutorials Source: https://docs.hanko.io/passkey-api/resources/tutorials End to end tutorials showcasing integration of Hanko Passkey API with different frameworks and libraries. } > Tutorial showing how to integrate passkeys in Next.js application using NextAuth. } > Tutorial showing how to integrate passkeys in Next.js application using Hanko Passkey SDK. } > Tutorial showing how to add passkeys in a Remix application. } > Tutorial showing how to integrate passkeys in T3 Stack application. } > Tutorial showing how to integrate passkeys in a React and Node application. } > Tutorial showing how to integrate passkeys in a Vue.js application with Express backend. } > Tutorial showing how to integrate passkeys in a Python Flask application. # Setting up a Passkey API project on Hanko Cloud Source: https://docs.hanko.io/passkey-api/setup-passkey-project This guide will walk you through the initial set up process of a Passkey API project on Hanko Cloud. To begin, head over to [Hanko](https://cloud.hanko.io/) and sign up. Once you've signed up, you'll be directed to create an organization. With your organization set, it's time to kick off a new Passkey project. Choose 'Passkey Infrastructure' and click 'Create Project'. Input your project name and provide your app's URL. For the app URL, make sure to enter the full URL including `http://` or `https://` and the port in case it's localhost, e.g. `http://localhost:3000`. Upon entering the dashboard, copy the Tenant ID and create an API key. You'll need these for future integrations. You're all set! Visit the next sections to kick off your integration journey. # Integrate Hanko with a Go backend Source: https://docs.hanko.io/quickstarts/backend/go Learn how to validate Hanko session tokens in your Go backend to secure API endpoints and authenticate users.
**Hanko Backend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to validate Hanko session tokens in your backend application. You'll learn to implement session validation, create middleware for protecting endpoints, and authenticate requests using Hanko's session management APIs. **Key Technologies**: * Server-side programming language * HTTP client libraries * Middleware frameworks * JSON handling * Hanko session validation API **Prerequisites**: * Knowledge of your chosen backend language and framework * Hanko Cloud account (sign up at cloud.hanko.io) * Frontend application with Hanko authentication **Integration Tasks You'll Complete**: * Set up Hanko API URL configuration from environment variables * Implement session token validation using proper data structures * Create reusable middleware or utilities for protecting API endpoints * Handle session validation responses, errors, and edge cases * Extract session tokens from HTTP cookies securely * Build authentication utilities that integrate with your application architecture * Implement comprehensive error handling and logging for production use
After successful authentication, Hanko generates a session token stored as a cookie. This guide shows how to validate these session tokens in your Go backend to authenticate API requests. ## Get the Hanko API URL Retrieve your project's API URL from the [Hanko Console](https://cloud.hanko.io/). This URL is used to validate session tokens. If you are self-hosting Hanko, use your self-hosted instance URL instead. ## Authentication flow To authenticate requests in your Go backend: 1. Extract the session token from the HTTP cookie 2. Validate the token using Hanko's [session validation API](/api-reference/public/session-management/validate-a-session-1) 3. Allow or deny the request based on validation result ## Implementation example This example shows how to create a session validator that can be used as middleware in your Go application: ```go theme={null} // SessionValidator defines the interface for session validation type SessionValidator interface { ValidateSession(token string) (bool, error) } // HankoSessionValidator implements SessionValidator type HankoSessionValidator struct { apiURL string } // ValidationResponse represents the Hanko API response type ValidationResponse struct { IsValid bool `json:"is_valid"` } func NewHankoSessionValidator(apiURL string) *HankoSessionValidator { return &HankoSessionValidator{apiURL: apiURL} } func (v *HankoSessionValidator) ValidateSession(token string) (bool, error) { payload := strings.NewReader(fmt.Sprintf(`{"session_token":"%s"}`, token)) req, err := http.NewRequest(http.MethodPost, v.apiURL+"/sessions/validate", payload) if err != nil { return false, fmt.Errorf("Failed to create request: %w", err) } req.Header.Add("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { return false, fmt.Errorf("Failed to send request: %w", err) } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { return false, fmt.Errorf("Failed to read response: %w", err) } var validationRes ValidationResponse if err := json.Unmarshal(body, &validationRes); err != nil { return false, fmt.Errorf("Failed to parse response: %w", err) } return validationRes.IsValid, nil } ``` ## Using the validator as middleware Here's how to use the session validator to protect your API endpoints: ```go theme={null} func AuthMiddleware(validator SessionValidator) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Extract session token from cookie cookie, err := r.Cookie("hanko") if err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } // Validate the session token isValid, err := validator.ValidateSession(cookie.Value) if err != nil { http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } if !isValid { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } // Continue to the next handler next.ServeHTTP(w, r) }) } } // Usage example func main() { validator := NewHankoSessionValidator("https://your-hanko-api-url.hanko.io") mux := http.NewServeMux() mux.HandleFunc("/protected", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("This is a protected endpoint!")) }) // Apply authentication middleware to protected routes http.ListenAndServe(":8080", AuthMiddleware(validator)(mux)) } ``` # Integrate Hanko with a Java/Spring backend Source: https://docs.hanko.io/quickstarts/backend/java_spring Learn how to validate Hanko session tokens in your Java/Spring backend to secure API endpoints and authenticate users.
**Hanko Backend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to validate Hanko session tokens in your backend application. You'll learn to implement session validation, create middleware for protecting endpoints, and authenticate requests using Hanko's session management APIs. **Key Technologies**: * Server-side programming language * HTTP client libraries * Middleware frameworks * JSON handling * Hanko session validation API **Prerequisites**: * Knowledge of your chosen backend language and framework * Hanko Cloud account (sign up at cloud.hanko.io) * Frontend application with Hanko authentication **Integration Tasks You'll Complete**: * Set up Hanko API URL configuration from environment variables * Implement session token validation using proper data structures * Create reusable middleware or utilities for protecting API endpoints * Handle session validation responses, errors, and edge cases * Extract session tokens from HTTP cookies securely * Build authentication utilities that integrate with your application architecture * Implement comprehensive error handling and logging for production use
After successful authentication, Hanko generates a session token stored as a cookie. This guide shows how to validate these session tokens in your Java/Spring backend to authenticate API requests. ## Get the Hanko API URL Retrieve your project's API URL from the [Hanko Console](https://cloud.hanko.io/). This URL is used to validate session tokens. If you are self-hosting Hanko, use your self-hosted instance URL instead. ## Authentication flow To authenticate requests in your Java/Spring backend: 1. Extract the session token from the HTTP cookie 2. Validate the token using Hanko's [session validation API](/api-reference/public/session-management/validate-a-session-1) 3. Allow or deny the request based on validation result ## Implementation example This example shows how to create a session validator that can be used as a filter in your Java/Spring application: ```java theme={null} import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestClient; import java.util.Arrays; import java.util.Map; public class HankoSessionValidationResponse { @JsonProperty("is_valid") private boolean isValid; public boolean isValid() { return isValid; } } @Component public class HankoSessionValidator { private static final Logger log = LoggerFactory.getLogger(HankoSessionValidator.class); private final RestClient restClient; private final String hankoBaseUrl; private final String hankoCookieName; public HankoSessionValidator( @Value("${hanko.baseUrl:}") String hankoBaseUrl, @Value("${hanko.cookieName:hanko}") String hankoCookieName, RestClient.Builder restClientBuilder ) { this.hankoBaseUrl = hankoBaseUrl != null ? hankoBaseUrl.replaceAll("/+$", "") : ""; this.hankoCookieName = hankoCookieName; this.restClient = restClientBuilder.build(); } public boolean isSessionValid(HttpServletRequest request) { if (hankoBaseUrl == null || hankoBaseUrl.isBlank()) { log.warn("Hanko base URL is not configured"); return false; } try { String token = extractSessionToken(request); if (token == null || token.isBlank()) { return false; } HankoSessionValidationResponse body = restClient.post() .uri(hankoBaseUrl + "/sessions/validate") .contentType(MediaType.APPLICATION_JSON) .body(Map.of("session_token", token)) .retrieve() .body(HankoSessionValidationResponse.class); return body != null && body.isValid(); } catch (HttpClientErrorException | HttpServerErrorException e) { if (e.getStatusCode().is4xxClientError()) { log.debug("Hanko session invalid: {}", e.getStatusCode()); } else { log.warn("Hanko validation error: {}", e.getStatusCode()); } return false; } catch (Exception e) { log.warn("Failed to validate Hanko session", e); return false; } } private String extractSessionToken(HttpServletRequest request) { // Cookie: hanko= (name configurable via hanko.cookieName) Cookie[] cookies = request.getCookies(); if (cookies != null) { return Arrays.stream(cookies) .filter(c -> hankoCookieName.equals(c.getName())) .map(Cookie::getValue) .filter(v -> v != null && !v.isBlank()) .findFirst() .orElse(null); } return null; } } ``` ## Using the validator as a Spring filter Create a filter to protect your routes using the session validator: ```java theme={null} import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; @Component public class HankoSessionFilter extends OncePerRequestFilter { private final HankoSessionValidator validator; public HankoSessionFilter(HankoSessionValidator validator) { this.validator = validator; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (!validator.isSessionValid(request)) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setContentType("application/json"); response.getWriter().write("{\"error\":\"unauthorized\"}"); return; } filterChain.doFilter(request, response); } } ``` Configure Spring to run the filter on all routes that should be protected: In this example only the `/secured` route is protected. ```java theme={null} import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; @Configuration public class SecurityConfig { @Bean public FilterRegistrationBean hankoSessionFilterRegistration(HankoSessionFilter filter) { FilterRegistrationBean registration = new FilterRegistrationBean<>(); registration.setFilter(filter); registration.setUrlPatterns(List.of("/secured")); registration.setOrder(1); return registration; } } ``` # Integrate Hanko with a JavaScript backend Source: https://docs.hanko.io/quickstarts/backend/javascript Learn how to validate Hanko session tokens in your JavaScript/Node.js backend to authenticate API requests.
**Hanko Backend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to validate Hanko session tokens in your backend application. You'll learn to implement session validation, create middleware for protecting endpoints, and authenticate requests using Hanko's session management APIs. **Key Technologies**: * Server-side programming language * HTTP client libraries * Middleware frameworks * JSON handling * Hanko session validation API **Prerequisites**: * Knowledge of your chosen backend language and framework * Hanko Cloud account (sign up at cloud.hanko.io) * Frontend application with Hanko authentication **Integration Tasks You'll Complete**: * Set up Hanko API URL configuration from environment variables * Implement session token validation using proper data structures * Create reusable middleware or utilities for protecting API endpoints * Handle session validation responses, errors, and edge cases * Extract session tokens from HTTP cookies securely * Build authentication utilities that integrate with your application architecture * Implement comprehensive error handling and logging for production use
After successful authentication, Hanko generates a session token stored as a cookie. This guide shows how to validate these session tokens in your JavaScript backend to authenticate API requests. ## Get the Hanko API URL Retrieve the API URL from the [Hanko Console](https://cloud.hanko.io/). If you are self-hosting Hanko you need to provide your own URL. ### Steps to authenticate requests 1. Retrieve the session token. 2. Verify the Session token using the Hanko [Validate](/api-reference/public/session-management/validate-a-session-1) API endpoint. ### Example function The following section demonstrates how to validate session tokens against the Hanko backend. The specific implementation for retrieving the session token cookie will vary depending on your JavaScript runtime environment and framework. ```ts index.ts theme={null} // Types and interfaces interface TokenValidator { validateToken(token: string): Promise; } interface ValidationResponse { is_valid: boolean; } // Token validator implementation class HankoTokenValidator implements TokenValidator { constructor(private readonly hankoApiUrl: string) {} async validateToken(token: string): Promise { if (!token || token.length === 0) { return false; } try { const response = await fetch(`${this.hankoApiUrl}/sessions/validate`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ session_token: token }), }); if (!response.ok) { return false; } const validationData = await response.json() as ValidationResponse; return validationData.is_valid; } catch (error) { console.error('Token validation error:', error); return false; } } } ``` ## Try it yourself } > Full source code available at GitHub. } > Full source code available at GitHub. } > Full source code available at GitHub. } > Full source code available at GitHub. # Integrate Hanko with a Python backend Source: https://docs.hanko.io/quickstarts/backend/python
**Hanko Backend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to validate Hanko session tokens in your backend application. You'll learn to implement session validation, create middleware for protecting endpoints, and authenticate requests using Hanko's session management APIs. **Key Technologies**: * Server-side programming language * HTTP client libraries * Middleware frameworks * JSON handling * Hanko session validation API **Prerequisites**: * Knowledge of your chosen backend language and framework * Hanko Cloud account (sign up at cloud.hanko.io) * Frontend application with Hanko authentication **Integration Tasks You'll Complete**: * Set up Hanko API URL configuration from environment variables * Implement session token validation using proper data structures * Create reusable middleware or utilities for protecting API endpoints * Handle session validation responses, errors, and edge cases * Extract session tokens from HTTP cookies securely * Build authentication utilities that integrate with your application architecture * Implement comprehensive error handling and logging for production use
After successful authentication, Hanko generates a session token that is stored as a cookie. Use the session token to authenticate requests to your backend. This guide shows how to implement session token validation in Python to ensure that only authenticated users can access your application's protected resources. ### Get the Hanko API URL Retrieve the API URL from the [Hanko Console](https://cloud.hanko.io/). If you are self-hosting Hanko you need to provide your own URL. ### Steps to authenticate requests 1. Retrieve the Session Token. 2. Verify the Session token using the Hanko [Validate](/api-reference/public/session-management/validate-a-session-1) API endpoint. ### Session token validation function The following function validates session tokens against the Hanko backend. The implementation for retrieving the session token cookie will vary depending on your framework. ```python theme={null} def validate_session_token(token: str) -> Tuple[bool, Optional[str]]: """ Validates a session token with the Hanko API. Returns a tuple of (is_valid: bool, error_message: Optional[str]) """ try: response = requests.post( f"{HANKO_API_URL}/sessions/validate", json={"session_token": token} ) if response.status_code != 200: return False, "Invalid token" validation_data = response.json() if not validation_data.get("is_valid", False): return False, "Invalid token" return True, None except requests.Timeout: return False, "Authentication service timeout" except requests.RequestException: return False, "Authentication service unavailable" ``` # Integrate Hanko with a Rust backend Source: https://docs.hanko.io/quickstarts/backend/rust
**Hanko Backend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to validate Hanko session tokens in your backend application. You'll learn to implement session validation, create middleware for protecting endpoints, and authenticate requests using Hanko's session management APIs. **Key Technologies**: * Server-side programming language * HTTP client libraries * Middleware frameworks * JSON handling * Hanko session validation API **Prerequisites**: * Knowledge of your chosen backend language and framework * Hanko Cloud account (sign up at cloud.hanko.io) * Frontend application with Hanko authentication **Integration Tasks You'll Complete**: * Set up Hanko API URL configuration from environment variables * Implement session token validation using proper data structures * Create reusable middleware or utilities for protecting API endpoints * Handle session validation responses, errors, and edge cases * Extract session tokens from HTTP cookies securely * Build authentication utilities that integrate with your application architecture * Implement comprehensive error handling and logging for production use
After successful authentication, Hanko generates a session token that is stored as a cookie. Use the session token to authenticate requests to your backend. This guide shows how to implement session token validation in Rust to ensure that only authenticated users can access your application's protected resources. ### Get the Hanko API URL Retrieve the API URL from the [Hanko Console](https://cloud.hanko.io/). If you are self-hosting Hanko you need to provide your own URL. ### Steps to authenticate requests 1. Retrieve the Session Token. 2. Verify the Session token using the Hanko [Validate](/api-reference/public/session-management/validate-a-session-1) API endpoint. ### Session token validation function The following code demonstrates how to validate session tokens against the Hanko backend. The implementation for retrieving the session token cookie will vary depending on your web framework. ```rust theme={null} use reqwest::Client; use serde::{Deserialize, Serialize}; // Configuration constants struct Config { hanko_api_url: String, } impl Config { fn new() -> Self { Self { hanko_api_url: std::env::var("HANKO_API_URL") .unwrap_or_else(|_| "YOUR_HANKO_API_URL".to_string()), } } } // Types #[derive(Serialize)] struct ValidationPayload<'a> { session_token: &'a str, } #[derive(Deserialize)] struct ValidationResponse { is_valid: bool, } async fn validate_token(token: &str, client: &Client, config: &Config) -> Result { let payload = ValidationPayload { session_token: token }; let url = format!("{}/sessions/validate", config.hanko_api_url); let resp = client.post(&url).json(&payload).send().await?; if !resp.status().is_success() { return Ok(false); } let validation_data: ValidationResponse = resp.json().await?; Ok(validation_data.is_valid) } ``` # Integrate Hanko with Angular Source: https://docs.hanko.io/quickstarts/frontend/angular Learn how to quickly add authentication and user profile in your Angular app using Hanko.
**Hanko Frontend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Hanko authentication into your frontend application. You'll implement user authentication, profile management, route protection, and logout functionality with Hanko Elements web components. **Key Technologies**: * Modern frontend framework with TypeScript support * Build tools and development environment * Client-side routing and navigation * Hanko Elements web components * Hanko SDK for authentication logic **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen frontend framework * A Hanko Cloud account (sign up at cloud.hanko.io) **Integration Tasks You'll Complete**: * Set up your frontend application with the appropriate build tools * Install and configure Hanko Elements * Create a Hanko project in the cloud console * Implement authentication components (HankoAuth, HankoProfile) * Set up routing and navigation * Add logout functionality * Implement protected routes with session validation * Retrieve and display user data * Customize component styling and behavior
## Create an Angular application Run the following command to [create a new Angular application](https://v17.angular.io/tutorial/tour-of-heroes/toh-pt0): ```bash npm theme={null} npm install -g @angular/cli ng new project-name --style=css --routing --standalone --defaults ``` ```bash pnpm theme={null} pnpm install -g @angular/cli ng new project-name --style=css --routing --standalone --defaults ``` ```bash bun theme={null} bun install -g @angular/cli ng new project-name --style=css --routing --standalone --defaults ``` ```bash yarn theme={null} yarn global add @angular/cli ng new project-name --style=css --routing --standalone --defaults ``` This quickstarts examples are based on the Server Routing and App Engine APIs. Make sure while creating your angular project you accept (press 'y') the routing and App Engine. ## Install `@teamhanko/hanko-elements` Install `hanko-elements` to access the pre-built `hanko-auth` and `hanko-profile` components. ```bash npm theme={null} cd project-name npm install @teamhanko/hanko-elements ``` ```bash pnpm theme={null} cd project-name pnpm add @teamhanko/hanko-elements ``` ```bash bun theme={null} cd project-name bun add @teamhanko/hanko-elements ``` ```bash yarn theme={null} cd project-name yarn add @teamhanko/hanko-elements ``` ## Set up Hanko project Go to the [Hanko Console](https://cloud.hanko.io/) and [create a project for this application.](/setup-hanko-cloud) During creation make sure to input the URL you will be developing on as the `APP URL`. (Most likely [http://localhost:4200/](http://localhost:4200/)) ## Set up environments Variables Create a new file `environments.ts` within your `/src` folder. Retrieve your API URL from the [Hanko Console](https://cloud.hanko.io/) and place it in your .env file. ```ts environments.ts theme={null} export const environment = { production: false, HANKO_API_URL: 'YOUR_HANKO_URL', }; ``` If you are self-hosting you need to provide the URL of your Hanko backend. ## Create Hanko components Create the `HankoAuth` and `HankoProfile` components by running these commands: ```bash theme={null} ng generate component HankoAuth --standalone ng generate component HankoProfile --standalone ``` Also generate two pages with these commands, we will add the components in here. ```bash theme={null} ng generate component Home --standalone --type=page ng generate component Dashboard --standalone --type=page ``` ### Hanko Auth Set up the `HankoAuth` component: For more information please refer to the [Auth component page.](/guides/hanko-elements/auth-component) ```html theme={null} ``` ```ts theme={null} //CUSTOM_ELEMENTS_SCHEMA lets you use the Hanko Elements import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { Router } from '@angular/router'; //function to register hanko element import { register } from "@teamhanko/hanko-elements"; import { environment } from '../../environments'; @Component({ //Selector you will use in the pages html files selector: 'app-hanko-auth', imports: [], templateUrl: './hanko-auth.component.html', styleUrl: './hanko-auth.component.css', schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class HankoAuthComponent { hankoApi = environment.HANKO_API_URL; constructor(private router: Router) { register(this.hankoApi).catch((error) => { // handle error }); } redirectAfterLogin() { //Succesfully logged in, redirect to any path you want. this.router.navigate(['/dashboard']); } } ``` Now Import the HankoAuth component into the home page you previously made. ```html theme={null} ``` ```ts theme={null} import { Component } from '@angular/core'; import { HankoAuthComponent } from '../hanko-auth/hanko-auth.component'; @Component({ selector: 'app-home', imports: [HankoAuthComponent],//Import the component into your page templateUrl: './home.page.html', styleUrl: './home.page.css' }) export class HomePage { } ``` ### Hanko Profile Set up the `HankoProfile` component to create an interface where users can manage their email addresses and credentials. For more information please refer to the [Profile component page.](/guides/hanko-elements/profile-component) ```html theme={null} ``` ```ts theme={null} //CUSTOM_ELEMENTS_SCHEMA lets you use the Hanko Elements import { Component , CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; //function to register hanko element import { register } from '@teamhanko/hanko-elements'; import { environment } from '../../environments'; @Component({ //Selector you will use in the pages html files selector: 'app-hanko-profile', imports: [], templateUrl: './hanko-profile.component.html', styleUrl: './hanko-profile.component.css', schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class HankoProfileComponent { hankoApi = environment.HANKO_API_URL; constructor() { register(this.hankoApi).catch((error) => { // handle error }); } } ``` Now Import the HankoAuth component into the dashboard page you previously made. ```html theme={null} ``` ```ts theme={null} import { Component } from '@angular/core'; import { HankoProfileComponent } from '../hanko-profile/hanko-profile.component'; @Component({ selector: 'app-dashboard', imports: [HankoProfileComponent],//Import the component into your page templateUrl: './dashboard.page.html', styleUrl: './dashboard.page.css' }) export class DashboardPage { } ``` ### Setting up routes Remove everything in the `app.component.html` file and add a router outlet. ```html app.component.html theme={null} ``` Now inport both pages into the `app.routes.ts` file and setup your routes. ```ts app.routes.ts theme={null} import { Routes } from '@angular/router'; import { HomePage } from './home/home.page'; import { DashboardPage } from './dashboard/dashboard.page'; export const routes: Routes = [ { path: '', component: HomePage, }, { path: 'dashboard', component: DashboardPage, }, ]; ``` By now you should be able to go to `/` to see the ``, and to `/dashboard` to see the ``. They should look something like this👇
sign up profile page
Use the command `ng serve` to start the server. ## Implement logout functionality You can use `@teamhanko/hanko-elements` to easily log users out. Here we will make a logout button component that you can use anywhere. Create the LogoutButton component with this command. ```bash theme={null} ng generate component LogoutButton --standalone ``` Now let's set up the LogoutButton component. ```html theme={null} ``` ```ts theme={null} import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { Hanko } from '@teamhanko/hanko-elements'; import { environment } from '../../environments'; @Component({ selector: 'app-logout-button', imports: [], templateUrl: './logout-button.component.html', styleUrl: './logout-button.component.css' }) export class LogoutButtonComponent { hankoApi = environment.HANKO_API_URL; constructor(private router: Router){}; logout(){ new Hanko(this.hankoApi).logout().catch((error) => { console.log(error); }).then(()=>{ //Url to navigate to once logged out this.router.navigate(["/"]); }); } } ``` Let's import this into our dashboard page. ```html theme={null} ``` ```ts theme={null} import { Component } from '@angular/core'; import { HankoProfileComponent } from '../hanko-profile/hanko-profile.component'; import { LogoutButtonComponent } from '../logout-button/logout-button.component'; @Component({ selector: 'app-dashboard', imports: [ HankoProfileComponent, LogoutButtonComponent//add the logout button ], templateUrl: './dashboard.page.html', styleUrl: './dashboard.page.css' }) export class DashboardPage { } ``` ## Customize component styles You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance). ## Securing routes To secure our routes we should validate the session token at the backend. Please refer to our [backend guides](/quickstarts/backend). Let's setup a `guard` that will check for authentication before the router activates the pages. Create the authentication guard with this command. ```bash theme={null} ng generate guard auth --implements CanActivate ``` Then in `auth.guard.ts`, insert this code. This will grab the hanko session token and send it to the backend for validation. ```ts theme={null} import { inject } from '@angular/core'; import { CanActivateFn, Router } from '@angular/router'; export const authGuard: CanActivateFn = async (route, state) => { const router = inject(Router); const backendUrl = "http://localhost:5001";//change this to the url of your running hanko backend const sessionToken = isBrowser() ? getCookie('hanko') : null; if (!sessionToken) throw new Error('No session token found.'); try { const response = await fetch(`${backendUrl}/validate`, { credentials: "include", }); if (!response.ok) throw new Error('Session validation failed'); return true; } catch (error) { console.error('AuthGuard error:', error); return router.parseUrl('/');// url to return the user to if they are not authenticated } }; function getCookie(name: string): string | null { if (typeof document === 'undefined') return null; const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`)); return match ? match[2] : null; } function isBrowser(): boolean { return typeof window !== 'undefined' && typeof document !== 'undefined'; } ``` Add this authentication guard to the routes, in the `app.routes.ts`, which should only be accessible when the user is logged in. ```ts app.routes.ts theme={null} import { Routes } from '@angular/router'; import { HomePage } from './home/home.page'; import { DashboardPage } from './dashboard/dashboard.page'; //Import the auth guard import { authGuard } from './auth.guard'; export const routes: Routes = [ { path: '', component: HomePage, }, { path: 'dashboard', component: DashboardPage, canActivate: [authGuard]//secure the /dashboard path with the guard }, ]; ``` To verify that it works, logout on your app and go to /dashboard, you should get redirected back! ## Getting user data Let's use the Hanko SDK to get user data to display on our dashboard page. For the user information we will use [hanko.getCurrentUser()](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/index.html#getting-the-user-object) Lets update our dashboard page. ```html theme={null}

Email: {{email}}

Id: {{id}}

```
```ts theme={null} import { Component } from '@angular/core'; import { HankoProfileComponent } from '../hanko-profile/hanko-profile.component'; import { LogoutButtonComponent } from '../logout-button/logout-button.component'; import { Hanko } from '@teamhanko/hanko-elements'; import { environment } from '../../environments'; @Component({ selector: 'app-dashboard', imports: [ HankoProfileComponent, LogoutButtonComponent//add the logout button ], templateUrl: './dashboard.page.html', styleUrl: './dashboard.page.css' }) export class DashboardPage { hankoApi = environment.HANKO_API_URL; email : string = ''; id : string = ''; ngOnInit(): void { const hanko = new Hanko(this.hankoApi); //Get user to get the user information hanko.getCurrentUser().then((user: any) => { this.email = user.emails?.[0]?.address || 'Unknown'; this.id = user.user_id || 'Unknown'; }).catch(err => console.error('Failed to fetch user', err)); } } ```
## Try it yourself } > It uses Express.js for the backend, full source code available on our GitHub. # Integrate Hanko with JavaScript Source: https://docs.hanko.io/quickstarts/frontend/javascript Learn how to quickly add authentication and user profile in your vanilla Javascript app using Hanko.
**Hanko Frontend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Hanko authentication into your frontend application. You'll implement user authentication, profile management, route protection, and logout functionality with Hanko Elements web components. **Key Technologies**: * Modern frontend framework with TypeScript support * Build tools and development environment * Client-side routing and navigation * Hanko Elements web components * Hanko SDK for authentication logic **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen frontend framework * A Hanko Cloud account (sign up at cloud.hanko.io) **Integration Tasks You'll Complete**: * Set up your frontend application with the appropriate build tools * Install and configure Hanko Elements * Create a Hanko project in the cloud console * Implement authentication components (HankoAuth, HankoProfile) * Set up routing and navigation * Add logout functionality * Implement protected routes with session validation * Retrieve and display user data * Customize component styling and behavior
## Add the Hanko API URL Retrieve the API URL from the [Hanko Console](https://cloud.hanko.io/) and place it in your `.env` file. ```sh .env theme={null} HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` If you are self-hosting, you need to provide the URL of your running Hanko backend. ## Add `` component Add the `` web component to create a login interface. Import the `register` function from `@teamhanko/hanko-elements` and call it with your Hanko API URL to register the component with the browser's [CustomElementRegistry](https://developer.mozilla.org/de/docs/Web/API/CustomElementRegistry). ```html login.html theme={null} ``` ## Define event callbacks Use the Hanko client to listen for specific [events](https://github.com/teamhanko/hanko/blob/main/frontend/elements/README.md#events) such as user logins. ```html login.html theme={null} ``` By now, your sign-up and sign-in features should be working. You should see an interface similar to this 👇 sign up ## Add `` The `` component provides an interface, where users can manage their email addresses and passkeys. ```html profile.html theme={null} ``` It should look like this 👇 profile page ## Implement logout functionality Implement logout functionality using the Hanko client. A custom event is dispatched on logout that you can subscribe to: ```html profile.html theme={null} ``` ## Customize component styles The styles of the `hanko-auth` and `hanko-profile` elements can be customized using CSS variables and parts. See our guide on customization [here](/guides/hanko-elements/customize-appearance). ## Authenticate backend requests To authenticate requests on your backend with Hanko, refer to our [backend guide](/quickstarts/backend). # Integrate Hanko with React Source: https://docs.hanko.io/quickstarts/frontend/react Learn how to quickly add authentication and user profile in your React app using Hanko.
**Hanko Frontend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Hanko authentication into your frontend application. You'll implement user authentication, profile management, route protection, and logout functionality with Hanko Elements web components. **Key Technologies**: * Modern frontend framework with TypeScript support * Build tools and development environment * Client-side routing and navigation * Hanko Elements web components * Hanko SDK for authentication logic **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen frontend framework * A Hanko Cloud account (sign up at cloud.hanko.io) **Integration Tasks You'll Complete**: * Set up your frontend application with the appropriate build tools * Install and configure Hanko Elements * Create a Hanko project in the cloud console * Implement authentication components (HankoAuth, HankoProfile) * Set up routing and navigation * Add logout functionality * Implement protected routes with session validation * Retrieve and display user data * Customize component styling and behavior
## Create a React application Set up your React frontend using [Vite](https://vite.dev/) as the build tool. Run the following command to [create a new Vite React application](https://vite.dev/guide/): ```bash npm theme={null} npm create vite@latest project-name -- --template react-ts ``` ```bash pnpm theme={null} pnpm create vite project-name --template react-ts ``` ```bash bun theme={null} bun create vite project-name --template react-ts ``` ```bash yarn theme={null} yarn create vite project-name --template react-ts ``` ## Install `@teamhanko/hanko-elements` Install `hanko-elements` to access the pre-built `hanko-auth` and `hanko-profile` components. Also install `react-router-dom` for navigation between pages and routes. ```bash npm theme={null} cd project-name npm install @teamhanko/hanko-elements react-router-dom ``` ```bash pnpm theme={null} cd project-name pnpm add @teamhanko/hanko-elements react-router-dom ``` ```bash bun theme={null} cd project-name bun add @teamhanko/hanko-elements react-router-dom ``` ```bash yarn theme={null} cd project-name yarn add @teamhanko/hanko-elements react-router-dom ``` ## Set up your Hanko project Go to the [Hanko Console](https://cloud.hanko.io/) and [create a project for this application.](/setup-hanko-cloud) During creation make sure to input the URL you will be developing on as the `APP URL`. (Most likely [http://localhost:5173/](http://localhost:5173/)) ## Add the Hanko API URL Retrieve the API URL from the [Hanko Console](https://cloud.hanko.io/) and place it in your [.env file](https://vite.dev/guide/env-and-mode). ```sh .env theme={null} VITE_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` If you are self-hosting you need to provide the URL of your running Hanko backend. ## Create Hanko components Create a folder called `components` and create two files in it, `HankoAuth.tsx` and `HankoProfile.tsx`. ### Typescript To get these elements to work with typescript, currently we must add the types to the project. To do do this, create a file called `custom.d.ts` and place it in your apps root / src folder. ```jsx src/custom.d.ts theme={null} import { HankoAuthElementProps, HankoProfileElementProps, HankoEventsElementProps } from "@teamhanko/hanko-elements"; declare module "react" { namespace JSX { interface IntrinsicElements { "hanko-auth": HankoAuthElementProps; "hanko-login": HankoAuthElementProps; "hanko-registration": HankoAuthElementProps; "hanko-profile": HankoProfileElementProps; "hanko-events": HankoEventsElementProps; } } } ``` ### Hanko Auth Now lets setup the `HankoAuth.tsx` file to create a functioning login page. Here we subscribe to the `onSessionCreated` [event](/guides/hanko-elements/using-frontend-sdk#events), this triggers when a user successfully logs in. You can use these event to perform any desired action (e.g. redirect to your dashboard). For more information please refer to the [Auth component page.](/guides/hanko-elements/auth-component) ```jsx components/HankoAuth.tsx theme={null} import { useEffect, useCallback, useMemo } from "react"; import { useNavigate } from 'react-router-dom'; import { register, Hanko } from "@teamhanko/hanko-elements"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; export default function HankoAuth() { const navigate = useNavigate(); const hanko = useMemo(() => new Hanko(hankoApi), []); const redirectAfterLogin = useCallback(() => { // redirect to a page in your application navigate("/dashboard"); }, [navigate]); useEffect( () => hanko?.onSessionCreated(() => { //succesfully logged in redirectAfterLogin(); }), [hanko, redirectAfterLogin] ); useEffect(() => { register(hankoApi).catch((error) => { // handle error console.log(error) }); }, []); return ; } ``` Now simply import the component you just created. ```jsx pages/loginPage.tsx theme={null} import HankoAuth from "../components/HankoAuth"; export default function LoginPage() { return ( ); } ``` ### Hanko Profile After setting up the HankoAuth let's set up the `HankoProfile.jsx` file to create an interface where users can manage their `Email Addresses` and credentials. For more information please refer to the [Profile component page.](/guides/hanko-elements/profile-component) ```jsx components/HankoProfile.tsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; export default function HankoProfile() { useEffect(() => { register(hankoApi).catch((error) => { // handle error console.log(error) }); }, []); return ; } ``` After you created the `HankoProfile` component, simply import it into any page. ```jsx pages/dashboardPage.tsx theme={null} import HankoProfile from "../components/HankoProfile"; export default function Dashboard() { return (
); } ``` ## Setup your routes After you created the `LoginPage.tsx` and `DashboardPage.tsx` you are able to import them into your react `App.tsx`. We will use `react-router-dom` to setup the routes of your app. ```jsx App.tsx theme={null} import './App.css' import { Route, createBrowserRouter, createRoutesFromElements, RouterProvider } from 'react-router-dom'; import LoginPage from './pages/loginPage'; import Dashboard from './pages/dashboardPage'; const router = createBrowserRouter( createRoutesFromElements( {/* index route with Login page*/} } /> {/* dashboard route with Dashboard page*/} } /> ) ) export default function App(){ return ( ) } ``` By now you should be able to go to `/` to see the ``, and to `/dashboard` to see the ``. They should look something like this👇
sign up profile page
## Implement logout functionality You can use `@teamhanko/hanko-elements` to easily logout users. Here we will make a logout button. Create `LogoutButton.tsx` and insert the code below. ```jsx components/LogoutButton.tsx theme={null} import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import { Hanko } from "@teamhanko/hanko-elements"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; function LogoutBtn() { const navigate = useNavigate(); const [hanko, setHanko] = useState(); useEffect(() => { import("@teamhanko/hanko-elements").then(({ Hanko }) => setHanko(new Hanko(hankoApi ?? "")) ); }, []); const logout = async () => { try { await hanko?.logout(); navigate("/"); //Path to naviage to once the user logs out. } catch (error) { console.error("Error during logout:", error); } }; return ; } export default LogoutBtn; ``` ## Customize component styles You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance). ## Securing routes To secure our routes we should validate the session token at the backend. Please refer to our [backend guides](/quickstarts/backend). Lets set up a Private route to do this for us. Create a new React component at `components/PrivateRoute.tsx`. If the backend couldn't validate our token we get navigated back to `/`. Otherwise if the validation was successfull it will return the children inside the private route. ```jsx components/PrivateRoute.tsx theme={null} import { ReactNode, useEffect, useState } from 'react'; import { Navigate, useLocation } from 'react-router-dom'; export default function PrivateRoute({ children }: { children: ReactNode }) { const [isAuthenticated, setIsAuthenticated] = useState(null); const location = useLocation(); useEffect(() => { fetch('http://localhost:5001/validate', {// Change this to the validation url of your running backend credentials: 'include', // This is required to include the cookie in the request }) .then((res) => { setIsAuthenticated(res.ok); }) .catch(() => { setIsAuthenticated(false); }); }, []); if (isAuthenticated === null) { return null; // Or a loading spinner } if(isAuthenticated){ return <>{children} } //Url to naviage user to if they arent authenticated return } ``` Lets import this `PrivateRoute.tsx` to your `App.tsx` file.\ To use the private route wrap your `Dashboard` in the Private Route; ```jsx App.tsx theme={null} import './App.css' import { Route, createBrowserRouter, createRoutesFromElements, RouterProvider } from 'react-router-dom'; import LoginPage from './pages/loginPage'; import Dashboard from './pages/dashboardPage'; import PrivateRoute from './components/PrivateRoute'; const router = createBrowserRouter( createRoutesFromElements( {/* index route with Login page*/} } /> {/* secured dashboard route with Dashboard page*/} } /> ) ) export default function App(){ return ( ) } ``` To verify that it works, logout on your app and go to `/dashboard`, you should get redirected back. ## Getting user data ### Client side Lets use the Hanko SDK to get user data. Lets update the `dashboard` page to log some of the information from the user. ```jsx pages/dashboardPage.tsx theme={null} import { useState, useEffect, useMemo } from "react"; import { Hanko } from "@teamhanko/hanko-elements"; import HankoProfile from "../components/HankoProfile"; const hankoApi = process.env.REACT_APP_HANKO_API_URL; export default function Dashboard() { const hanko = useMemo(() => new Hanko(hankoApi), []); useEffect(() => setHanko(new Hanko(hankoApi)), []); useEffect(() => { hanko?.getCurrentUser() .then((user) => { console.log("User profile:", user);// Log user Profile console.log(user.emails?.[0]?.address); console.log(user.user_id); }) }, [hanko]); return (
); } ``` ## Try it yourself } > It uses Express.js for the backend, full source code available on our GitHub. # Integrate Hanko with Solid Source: https://docs.hanko.io/quickstarts/frontend/solid Learn how to quickly add authentication and user profile in your Solid app using Hanko.
**Hanko Frontend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Hanko authentication into your frontend application. You'll implement user authentication, profile management, route protection, and logout functionality with Hanko Elements web components. **Key Technologies**: * Modern frontend framework with TypeScript support * Build tools and development environment * Client-side routing and navigation * Hanko Elements web components * Hanko SDK for authentication logic **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen frontend framework * A Hanko Cloud account (sign up at cloud.hanko.io) **Integration Tasks You'll Complete**: * Set up your frontend application with the appropriate build tools * Install and configure Hanko Elements * Create a Hanko project in the cloud console * Implement authentication components (HankoAuth, HankoProfile) * Set up routing and navigation * Add logout functionality * Implement protected routes with session validation * Retrieve and display user data * Customize component styling and behavior
## Install `@teamhanko/hanko-elements` Install `hanko-elements` to access the pre-built `hanko-auth` and `hanko-profile` components. ```bash npm theme={null} npm install @teamhanko/hanko-elements ``` ```bash pnpm theme={null} pnpm add @teamhanko/hanko-elements ``` ```bash bun theme={null} bun add @teamhanko/hanko-elements ``` ```bash yarn theme={null} yarn add @teamhanko/hanko-elements ``` ## Add the Hanko API URL Retrieve the API URL from the [Hanko Console](https://cloud.hanko.io/) and place it in your .env file. ```sh .env theme={null} VITE_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` If you are self-hosting you need to provide the URL of your running Hanko backend. ## Add `` component Add the `` web component to create a login interface. Import the `register` function from `@teamhanko/hanko-elements` and call it with your Hanko API URL to register the component with the browser's [CustomElementRegistry](https://developer.mozilla.org/de/docs/Web/API/CustomElementRegistry). ```tsx components/HankoAuth.tsx theme={null} import { onMount, createSignal, onCleanup } from "solid-js"; import { register, Hanko } from "@teamhanko/hanko-elements"; import { useNavigate } from "@solidjs/router"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; export default function HankoAuth() { const navigate = useNavigate(); const hanko = new Hanko(hankoApi); const redirectAfterLogin = () => { navigate("/dashboard"); }; onMount(() => { hanko.onSessionCreated(() => { redirectAfterLogin(); }); register(hankoApi).catch((error) => { // handle error }); }); onCleanup(() => { // cleanup logic if needed }); return ; } type GlobalJsx = JSX.IntrinsicElements; declare module "solid-js" { namespace JSX { interface IntrinsicElements { "hanko-auth": GlobalJsx["hanko-auth"]; } } } ``` By now, your sign-up and sign-in features should be working. You should see an interface similar to this 👇 sign up ## Add `` component The `` component provides an interface, where users can manage their email addresses and passkeys. ```tsx components/HankoProfile.tsx theme={null} import { onMount } from "solid-js"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; export default function HankoProfile() { onMount(() => { register(hankoApi).catch((error) => { // handle error }); }); return ; } type GlobalJsx = JSX.IntrinsicElements; declare module "solid-js" { namespace JSX { interface IntrinsicElements { "hanko-profile": GlobalJsx["hanko-profile"]; } } } ``` It should look like this 👇 profile page ## Implement logout functionality Create a logout button component using `@teamhanko/hanko-elements` to manage user logouts: ```tsx components/LogoutButton.tsx theme={null} import { useNavigate } from "@solidjs/router"; import { Hanko } from "@teamhanko/hanko-elements"; const hankoApi = import.meta.env.VITE_HANKO_API_URL; function LogoutBtn() { const navigate = useNavigate(); let hanko = new Hanko(hankoApi ?? ""); const logout = async () => { try { await hanko.user.logout(); navigate("/auth"); } catch (error) { console.error("Error during logout:", error); } }; return ; } export default LogoutBtn; ``` ## Customize component styles You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance). ## Authenticate backend requests To authenticate requests on your backend with Hanko, refer to our [backend guide](/quickstarts/backend). ## Try it yourself } > It uses Express.js for the backend, full source code available on our GitHub. # Integrate Hanko with Svelte Source: https://docs.hanko.io/quickstarts/frontend/svelte Learn how to quickly add authentication and user profile in your Svelte app using Hanko.
**Hanko Frontend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Hanko authentication into your frontend application. You'll implement user authentication, profile management, route protection, and logout functionality with Hanko Elements web components. **Key Technologies**: * Modern frontend framework with TypeScript support * Build tools and development environment * Client-side routing and navigation * Hanko Elements web components * Hanko SDK for authentication logic **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen frontend framework * A Hanko Cloud account (sign up at cloud.hanko.io) **Integration Tasks You'll Complete**: * Set up your frontend application with the appropriate build tools * Install and configure Hanko Elements * Create a Hanko project in the cloud console * Implement authentication components (HankoAuth, HankoProfile) * Set up routing and navigation * Add logout functionality * Implement protected routes with session validation * Retrieve and display user data * Customize component styling and behavior
## Create a Svelte application Set up your Svelte frontend using [Vite](https://vite.dev/) as the build tool. Run the following command to [create a new Vite Svelte application](https://vite.dev/guide/): ```bash npm theme={null} npm create vite@latest project-name -- --template svelte-ts ``` ```bash pnpm theme={null} pnpm create vite project-name --template svelte-ts ``` ```bash bun theme={null} bun create vite project-name --template svelte-ts ``` ```bash yarn theme={null} yarn create vite project-name --template svelte-ts ``` ## Install `@teamhanko/hanko-elements` Install `hanko-elements` to access the pre-built `hanko-auth` and `hanko-profile` components. Also install the `svelte-routing` package to handle routing and navigation. ```bash npm theme={null} cd project-name npm install @teamhanko/hanko-elements svelte-routing ``` ```bash pnpm theme={null} cd project-name pnpm add @teamhanko/hanko-elements svelte-routing ``` ```bash bun theme={null} cd project-name bun add @teamhanko/hanko-elements svelte-routing ``` ```bash yarn theme={null} cd project-name yarn add @teamhanko/hanko-elements svelte-routing ``` ## Set up your Hanko project Go to the [Hanko Console](https://cloud.hanko.io/) and [create a project for this application.](/setup-hanko-cloud) During creation make sure to input the URL you will be developing on as the `APP URL`. (Most likely [http://localhost:5173/](http://localhost:5173/)) ## Add the Hanko API URL Retrieve the API URL from the [Hanko Console](https://cloud.hanko.io/) and place it in your .env file. ```sh .env theme={null} VITE_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` If you are self-hosting you need to provide the URL of your running Hanko backend. ## Create Hanko components Create a folder called `components` and create two files in it, `HankoAuth.svelte` and `HankoProfile.svelte`. ### Hanko Auth Set up the `HankoAuth.svelte` file to create a functioning login component. [For more information please refer to the Auth Component Page.](/guides/hanko-elements/auth-component) ```jsx components/HankoAuth.svelte theme={null} ``` After you created the `HankoAuth` component, import and add it in any page.\ Just like this. ```tsx pages/HomePage.svelte theme={null} ``` ### Hanko Profile Set up the `HankoProfile.svelte` file to create an interface where users can manage their email addresses and credentials. [For more information please refer to the Profile Component Page.](/guides/hanko-elements/profile-component) ```jsx components/HankoAuth.svelte theme={null} ``` After you created the `HankoProfile` component, simply import it into any page.\ In our case we created a dashboardPage.svelte file to show the HankoProfile as our Hanko Auth redirects to `/dashboard`. ```jsx pages/dashboardPage.svelte theme={null} ``` ## Set up your routes After you created the `HomePage.svelte` and `DashboardPage.svelte` you are able to import them into your svelte `App.svelte`. We will use `svelte-router` to setup the routes of your app. ```jsx App.svelte theme={null} ``` By now you should be able to go to `/` to see the ``, and to `/dashboard` to see the ``. They should look something like this👇
sign up profile page
## Implement logout functionality You can use `@teamhanko/hanko-elements` to easily log users out. Here we will make a logout button component that you can use anywhere. For this QuickStart we will create a file at `components/LogoutButton.svelte` and insert the code below. ```jsx components/LogoutButton.svelte theme={null} ``` ## Customize component styles You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance). ## Securing routes To secure our routes we should validate the session token at the backend. Please refer to our [backend guides](/quickstarts/backend). Let's set up a Protected route to do this for us. Create a new Svelte component at `components/ProtectedRoute.svelte`. ```jsx components/ProtectedRoute.svelte theme={null} ``` Let's import this `ProtectedRoute.svelte` to your `App.svelte` file.\ To use the Protected route wrap your `Dashboard` in the Protected Route; ```jsx App.svelte theme={null} ``` ## Getting user and session data Lets use the Hanko SDK to Get User Data to display on the dashboard. For the User Information we will use [hanko.getCurrentUser()](https://teamhanko.github.io/hanko/jsdoc/hanko-frontend-sdk/index.html#getting-the-user-object) Lets update the `dashboard` page to log some of the information from the User And Session. ```jsx pages/DashboardPage.svelte theme={null}

{email}

{id}

``` ## Try it yourself } > It uses Express.js for the backend, full source code available on our GitHub. # Integrate Hanko with Vue Source: https://docs.hanko.io/quickstarts/frontend/vue Learn how to quickly add authentication and user profile in your Vue app using Hanko.
**Hanko Frontend Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This guide demonstrates how to integrate Hanko authentication into your frontend application. You'll implement user authentication, profile management, route protection, and logout functionality with Hanko Elements web components. **Key Technologies**: * Modern frontend framework with TypeScript support * Build tools and development environment * Client-side routing and navigation * Hanko Elements web components * Hanko SDK for authentication logic **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen frontend framework * A Hanko Cloud account (sign up at cloud.hanko.io) **Integration Tasks You'll Complete**: * Set up your frontend application with the appropriate build tools * Install and configure Hanko Elements * Create a Hanko project in the cloud console * Implement authentication components (HankoAuth, HankoProfile) * Set up routing and navigation * Add logout functionality * Implement protected routes with session validation * Retrieve and display user data * Customize component styling and behavior
## Create a Vue application Run the following command to [create a new Vue application with vite](https://vite.dev/guide/): ```bash npm theme={null} npm create vite@latest project-name -- --template vue-ts ``` ```bash pnpm theme={null} pnpm create vite project-name --template vue-ts ``` ```bash bun theme={null} bun create vite project-name --template vue-ts ``` ```bash yarn theme={null} yarn create vite project-name --template vue-ts ``` ## Install `@teamhanko/hanko-elements` Install `hanko-elements` to access the pre-built `hanko-auth` and `hanko-profile` components. Also install `vue-router` to handle routing and navigation. ```bash npm theme={null} cd project-name npm install @teamhanko/hanko-elements vue-router ``` ```bash pnpm theme={null} cd project-name pnpm add @teamhanko/hanko-elements vue-router ``` ```bash bun theme={null} cd project-name bun add @teamhanko/hanko-elements vue-router ``` ```bash yarn theme={null} cd project-name yarn add @teamhanko/hanko-elements vue-router ``` ## Set up your Hanko project Go to the [Hanko Console](https://cloud.hanko.io/) and [create a project for this application.](/setup-hanko-cloud) During creation make sure to input the URL you will be developing on as the `APP URL`.\ (Most likely [http://localhost:5173/](http://localhost:5173/)) ## Add the Hanko API URL Retrieve your API URL from the [Hanko Console](https://cloud.hanko.io/), and paste this in a `.env` file. ```sh .env theme={null} VITE_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` If you are self-hosting you need to provide the URL of your running Hanko backend. ## Configure component resolution Vue needs to know which elements to treat as custom elements, otherwise it will issue a warning regarding component resolution. To do so, provide a predicate function that determines which elements are to be considered custom elements to [`compilerOptions.isCustomElement`](https://vuejs.org/guide/extras/web-components.html#using-custom-elements-in-vue) in your configuration.\ \ To do this update your `vite.config.js` file to: ```js src/vite.config.js theme={null} import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith("hanko-") } } })], }) ``` ## Set up TS support for Vue components TypeScript doesn't understand .vue files by default, which can cause IDE errors or issues during development. To fix this we will create a new file `shims-vue.d.ts` in our `src/` directory. Add the following content to make TS understand .vue files: ```jsx src/shims-vue.d.ts theme={null} declare module '*.vue' { import type { DefineComponent } from 'vue' const component: DefineComponent<{}, {}, any> export default component } ``` ## Create Hanko components Create a folder called `components` and create two in it, `HankoAuth.vue` and `HankoProfile.vue`. ### Hanko Auth Set up the `HankoAuth.vue` file to create a functioning login component. Here we subscribe to the `onSessionCreated` [event](/guides/hanko-elements/using-frontend-sdk#events), this triggers when a user successfully logs in. You can use these event to perform any desired action (e.g. redirect to your dashboard). For more information please refer to the [Auth component page.](/guides/hanko-elements/auth-component) ```jsx src/components/HankoAuth.vue theme={null} ``` ### Hanko Profile Set up the `HankoProfile.vue` file to create an interface where users can manage their email addresses and credentials. For more information please refer to the [Profile component page.](/guides/hanko-elements/profile-component) ```jsx src/components/HankoProfile.vue theme={null} ``` ## Set up routes and views To route our app we will use the `RouterView` component from the vue-router. First let's set up our views which will be used by the router. ### Create Views Create two files, `HomeView.vue` and `DashboardView.vue` in a new directory `/views`. These Views will be the content that will be shown on a page.\ \ Setup your views like this: ```jsx src/views/HomeView.vue theme={null} ``` And: ```jsx src/views/DashboardView.vue theme={null} ``` ### Set up router Create a file `index.ts` in a new directory `/router`. In here we can set up the `vue-router` just like this: ```jsx router/index.ts theme={null} import { createRouter, createWebHistory } from 'vue-router' import HomeView from '../views/HomeView.vue'; import DashboardView from '../views/DashboardView.vue'; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', // <- path name: 'home', component: HomeView // <- view }, { path: '/dashboard', // <- path name: 'dashboard', component: DashboardView // <- view } ] }) export default router ``` Add the `` component to your `App.vue` file like this: ```jsx src/App.vue theme={null} ``` Finally intergrate the router with the app in `main.ts` just like this: ```jsx src/main.ts theme={null} import { createApp } from 'vue' import App from './App.vue' import router from './router/index' const app = createApp(App) app.use(router) app.mount('#app') ``` By now you should be able to go to `/` to see the ``, and to `/dashboard` to see the ``. They should look something like this👇
sign up profile page
If `HankoAuth` is not loading please restart the application as it might've not loaded the .env correctly the first time.\ \ `HankoProfile` will only look like the picture while you are logged in. ## Implement logout functionality You can use `@teamhanko/hanko-elements` to easily logout users. Here we will make a logout button. Create `LogoutButton.vue` and insert the code below. ```jsx src/components/LogoutButton.vue theme={null} ``` Lets add this component to our `DashboardView` just like this: ```jsx src/views/DashboardView.vue theme={null} ``` ## Customize component styles You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance). ## Securing routes To secure our routes we should validate the session token at the backend. Please refer to our [backend guides](/quickstarts/backend). To do this we can implement middleware to our `router/index.ts` file. For this example we created a `isUserAuthenticated` function which validates our cookie using our Backend. Here we use `router.beforeEach` to validate our route if our route is added to the secureRoutes variable: ```jsx src/router/index.ts theme={null} import { createRouter, createWebHistory } from 'vue-router' import HomeView from '../views/HomeView.vue'; import DashboardView from '../views/DashboardView.vue'; //Routes we want to only be accesible to authenticated users const securedRoutes = ["dashboard"]; async function isUserAuthenticated() { try { //Change this url to the url of your running hanko backend const response = await fetch('http://localhost:5001/validate', { credentials: 'include', }); return response.ok; } catch (error) { return false; } } const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', // <- path name: 'home', component: HomeView // <- view }, { path: '/dashboard', // <- path name: 'dashboard', component: DashboardView // <- view } ] }) //Middleware that runs before each navigation router.beforeEach(async (to, from, next) => { //Check if you are on a secure route if (typeof to.name === "string" && securedRoutes.includes(to.name) && !(await isUserAuthenticated())) { next({ name: 'home' }); //Name of the route to redirect to if user is not authenticated } else { next(); } }); export default router ``` To verify that it works, Logout on your app and go to /dashboard, you should get redirected back! ## Try it yourself } > It uses Express.js for the backend, full source code available on our GitHub. # Integrate Hanko with Next.js Source: https://docs.hanko.io/quickstarts/fullstack/next Learn how to quickly add authentication and a user profile to your Next.js app using Hanko.
**Hanko Fullstack Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This comprehensive guide demonstrates integrating Hanko authentication into your fullstack application using the `@teamhanko/hanko-elements` package. You'll learn to set up authentication components, implement session management, secure routes with middleware, and handle user data across both client and server-side contexts. **Key Technologies**: * Modern fullstack framework with TypeScript, * Server-side rendering capabilities * Hanko Elements * Hanko Cloud Console * Session management * Middleware protection **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen fullstack framework * A Hanko Cloud account (sign up at [https://cloud.hanko.io/signup](https://cloud.hanko.io/signup)) **Integration Tasks You'll Complete**: * Install and configure Hanko Elements package for your framework * Set up HankoAuth component with session event handling and navigation * Create HankoProfile component for user credential management * Implement logout functionality with proper session cleanup and redirects * Secure routes using framework-specific middleware with session validation * Retrieve user data both client-side and server-side using appropriate APIs * Handle authentication redirects, error states, and edge cases * Configure server-side rendering integration and hydration * Customize component appearance and behavior for your application
## Create a Next.js application Run the following command to [create a new Next.js application](https://nextjs.org/docs/app/getting-started/installation): When setting up Next.js, you’ll choose either the [App Router](https://nextjs.org/docs/app) or the [Pages Router](https://nextjs.org/docs/pages). Be sure to follow the proper directory structure and add the matching code for the router you selected. This creates a new Next.js application using the latest version and default settings. ```bash terminal theme={null} npx create-next-app@latest project-name ``` ## Install `@teamhanko/hanko-elements` Once you've initialized your NextJS app, installing hanko-elements provides you with access to the prebuilt components: `hanko-auth` and `hanko-profile`. This installs the Hanko Elements package, providing pre-built authentication components. ```bash npm theme={null} cd project-name npm install @teamhanko/hanko-elements ``` ```bash pnpm theme={null} cd project-name pnpm add @teamhanko/hanko-elements ``` ```bash bun theme={null} cd project-name bun add @teamhanko/hanko-elements ``` ```bash yarn theme={null} cd project-name yarn add @teamhanko/hanko-elements ``` ## Set up your Hanko project Go to the [Hanko Console](https://cloud.hanko.io/) and [create a project for this application.](/setup-hanko-cloud) During creation make sure to input the URL you will be developing on as the `APP URL`. (Most likely [http://localhost:3000](http://localhost:3000)) ## Add your Hanko API URL Retrieve your API URL from the [Hanko Console](https://cloud.hanko.io/), and paste this in a `.env` file. Set up your environment variable for the Hanko API URL. The NEXT\_PUBLIC\_ prefix makes it accessible in the browser. ```sh .env.local theme={null} NEXT_PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` If you are self-hosting you need to provide the URL of your running Hanko backend. ## Create Hanko components Create a folder called `components` and create two files, `HankoAuth.tsx` and `HankoProfile.jsx`. ### Add Typescript types To get these elements to work with typescript, currently we must add the types to the project. To do do this, create a file called `custom.d.ts` and place it in your apps root / src folder. Add TypeScript declarations for Hanko Web Components to enable type checking and IntelliSense support. ```jsx src/custom.d.ts theme={null} import { HankoAuthElementProps, HankoProfileElementProps, HankoEventsElementProps } from "@teamhanko/hanko-elements"; declare module "react" { namespace JSX { interface IntrinsicElements { "hanko-auth": HankoAuthElementProps; "hanko-login": HankoAuthElementProps; "hanko-registration": HankoAuthElementProps; "hanko-profile": HankoProfileElementProps; "hanko-events": HankoEventsElementProps; } } } ``` ### Login page with `` Now lets setup the `HankoAuth.tsx` file to create a functioning login page. Here we subscribe to the `onSessionCreated` [event](/guides/hanko-elements/using-frontend-sdk#events), this triggers when a user successfully logs in. You can use these event to perform any desired action. (e.g. redirect to your dashboard). For more information please refer to the [Auth component page.](/guides/hanko-elements/auth-component) App Router version: This authentication component handles session events and redirects users after successful login. ```jsx components/HankoAuth.tsx theme={null} "use client"; //Only for NextJS App Router import { useEffect, useCallback, useState } from "react"; import { useRouter } from "next/navigation"; import { register, Hanko } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ''; export default function HankoAuth() { const router = useRouter(); const [hanko, setHanko] = useState(); useEffect(() => setHanko(new Hanko(hankoApi)), []); const redirectAfterLogin = useCallback(() => { // change this to the page you wish to be redirected to router.replace("/dashboard"); }, [router]); useEffect( () => hanko?.onSessionCreated(() => { // successfully logged in redirectAfterLogin(); }), [hanko, redirectAfterLogin] ); useEffect(() => { register(hankoApi).catch((error) => { // handle error console.log(error); }); }, []); return ; } ``` Pages Router version: This authentication component uses next/router instead of next/navigation. ```jsx components/HankoAuth.tsx theme={null} import { useEffect, useCallback, useState } from "react"; import { useRouter } from "next/router"; import { register, Hanko } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ''; export default function HankoAuth() { const router = useRouter(); const [hanko, setHanko] = useState(); useEffect(() => setHanko(new Hanko(hankoApi)), []); const redirectAfterLogin = useCallback(() => { // change this to the page you wish to be redirected to router.replace("/dashboard"); }, [router]); useEffect( () => hanko?.onSessionCreated(() => { //succesfully logged in redirectAfterLogin(); }), [hanko, redirectAfterLogin] ); useEffect(() => { register(hankoApi).catch((error) => { // handle error console.log(error) }); }, []); return ; } ``` Now simply import the component you just created. App Router login page that renders the HankoAuth component. ```jsx app/login/page.tsx theme={null} import HankoAuth from "@/components/HankoAuth"; export default function LoginPage() { return ( ); } ``` Pages Router login page that renders the HankoAuth component. ```jsx pages/login.tsx theme={null} import HankoAuth from "@/components/HankoAuth"; export default function LoginPage() { return ( ); } ``` By now, your sign-up and sign-in features should be working. You should see an interface similar to this 👇 sign up ### Profile page with `` After setting up `HankoAuth`, let's set up the `HankoProfile.jsx` file to create an interface where users can manage their email addresses and login methods. For more information please refer to the [Profile component page.](/guides/hanko-elements/profile-component) App Router profile component for managing user emails and credentials. ```jsx components/HankoProfile.jsx theme={null} "use client" //Only for NextJS App Router import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ''; export default function HankoProfile() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` Pages Router profile component for managing user emails and credentials. ```jsx components/HankoProfile.jsx theme={null} import { useEffect } from "react"; import { register } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ''; export default function HankoProfile() { useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return ; } ``` After you created the `HankoProfile` component, simply import it into any page. ```jsx app/dashboard/page.tsx theme={null} import HankoProfile from "@/components/HankoProfile"; export default function Dashboard() { return (
); } ```
```jsx pages/dashboard.tsx theme={null} import HankoProfile from "@/components/HankoProfile"; export default function Dashboard() { return (
); } ```
It should look something like this 👇 profile page ## Implement logout functionality You can use `@teamhanko/hanko-elements` to easily logout users. Here we will make a logout button. Create `LogoutButton.tsx` and insert the code below. App Router logout button component that handles session cleanup and navigation. ```jsx components/LogoutButton.tsx theme={null} "use client"; //Only for NextJS App Router import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { Hanko } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ''; export default function LogoutBtn() { const router = useRouter(); const [hanko, setHanko] = useState(); useEffect(() => setHanko(new Hanko(hankoApi ?? "")), []); const logout = async () => { try { await hanko?.logout(); router.push("/"); router.refresh(); return; } catch (error) { console.error("Error during logout:", error); } }; return ; } ``` Pages Router logout button component using router.reload() instead of refresh(). ```jsx components/LogoutButton.tsx theme={null} import { useState, useEffect } from "react"; import { useRouter } from "next/router"; import { Hanko } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ''; export default function LogoutBtn() { const router = useRouter(); const [hanko, setHanko] = useState(); useEffect(() => setHanko(new Hanko(hankoApi ?? "")), []); const logout = async () => { try { await hanko?.logout(); router.push("/"); router.reload(); return; } catch (error) { console.error("Error during logout:", error); } }; return ; } ``` ## Customize component styles You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance). ## Securing routes with middleware To verify the session token in your Next.js application, we're using the [session/validate API request](/api-reference/public/session-management/validate-a-session). By checking for a valid session token this middleware will ensure secure access to specific routes, like `/dashboard` and `/protected`.\ The middleware extracts and verifies the session token, and redirect unauthorized users back to the home or login page. For more info on middlewares and where to put the `middleware.ts` file,\ please refer to [NextJS Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware). Middleware tends to not always work after creating it, if this is the case try restarting your next app. This Next.js middleware protects routes by validating Hanko session tokens. ```jsx middleware.ts theme={null} import { NextResponse, NextRequest } from "next/server"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export async function middleware(req: NextRequest) { const token = req.cookies.get("hanko")?.value; const validationOptions = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: `{"session_token":"${token}"}` } try { const validationResponse = await fetch( new URL(`${hankoApi}/sessions/validate`),//Hanko session validation validationOptions ); if (!validationResponse.ok) { throw new Error('Session validation failed'); } const responseData = await validationResponse.json(); if(!responseData.is_valid){ throw new Error('Session token not valid'); } } catch (error) { console.log(error) return NextResponse.redirect(new URL("/", req.url));// URL to redirect the user to } } export const config = { matcher: ["/dashboard"], }; ``` To verify that it works, logout on your app and go to `/dashboard`, you should get redirected back. ## Getting user data ### Client side Lets use the Hanko SDK to get user data. Lets update the `dashboard` page to log some of the information from the user and session. App Router dashboard with client-side user data retrieval using the Hanko SDK. ```jsx app/dashboard/page.tsx theme={null} "use client" //Only for NextJS App Router import HankoProfile from "../components/HankoProfile"; import LogoutButton from "../components/LogoutButton"; import { Hanko } from "@teamhanko/hanko-elements"; import { useState, useEffect } from "react"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ""; export default function Dashboard() { const [hanko, setHanko] = useState(); useEffect(() => setHanko(new Hanko(hankoApi)), []); useEffect(() => { hanko?.getCurrentUser() .then((user) => { console.log("User profile:", user);// Log user Profile console.log(user.emails?.[0]?.address); console.log(user.user_id); }) }, [hanko]); return (
); } ```
Pages Router dashboard with client-side user data retrieval. ```jsx pages/dashboard.tsx theme={null} import HankoProfile from "@/components/HankoProfile"; import LogoutButton from "@/components/LogoutButton"; import { Hanko } from "@teamhanko/hanko-elements"; import { useState, useEffect } from "react"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ""; export default function Dashboard() { const [hanko, setHanko] = useState(); useEffect(() => setHanko(new Hanko(hankoApi)), []); useEffect(() => { hanko?.getCurrentUser() .then((user) => { console.log("User profile:", user);// Log user Profile console.log(user.emails?.[0]?.address); console.log(user.user_id); }) }, [hanko]); return (
); } ```
### Server side On the server side, you can extract the `userID` from the session token, which you can use to fetch the user's data from the [Hanko Public API](/api-reference/public/user-management/get-a-user-by-id). This server-side function validates sessions and fetches user data using the Hanko API. ```ts getUserData.ts theme={null} import { cookies } from "next/headers"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ''; export async function getUserData() { try { const token = (await cookies()).get("hanko")?.value; const validationOptions = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: `{"session_token":"${token}"}` } const validationResponse = await fetch(hankoApi + '/sessions/validate', validationOptions); //Get session data if (!validationResponse.ok) { throw new Error("validation was not succesfull"); } const validationData = await validationResponse.json(); if(!validationData.is_valid){ //Validate session data throw new Error("validation was not succesfull"); } const userid = validationData.user_id; //use user id to request data const userResponse = await fetch(hankoApi + '/users/' + userid, validationOptions); if (!userResponse.ok) { throw new Error("Could not get user data"); } const userData = await userResponse.json(); return userData; } catch (error) { console.log(error) return null; } } ``` ## Try it yourself } > Full source code available on our GitHub } > Full source code available on our GitHub. # Integrate Hanko with Nuxt Source: https://docs.hanko.io/quickstarts/fullstack/nuxt Learn how to quickly add authentication and user profile in your Nuxt app using Hanko.
**Hanko Fullstack Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This comprehensive guide demonstrates integrating Hanko authentication into your fullstack application using the `@teamhanko/hanko-elements` package. You'll learn to set up authentication components, implement session management, secure routes with middleware, and handle user data across both client and server-side contexts. **Key Technologies**: * Modern fullstack framework with TypeScript, * Server-side rendering capabilities * Hanko Elements * Hanko Cloud Console * Session management * Middleware protection **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen fullstack framework * A Hanko Cloud account (sign up at [https://cloud.hanko.io/signup](https://cloud.hanko.io/signup)) **Integration Tasks You'll Complete**: * Install and configure Hanko Elements package for your framework * Set up HankoAuth component with session event handling and navigation * Create HankoProfile component for user credential management * Implement logout functionality with proper session cleanup and redirects * Secure routes using framework-specific middleware with session validation * Retrieve user data both client-side and server-side using appropriate APIs * Handle authentication redirects, error states, and edge cases * Configure server-side rendering integration and hydration * Customize component appearance and behavior for your application
## Create a Nuxt application First, create a new Nuxt.js application using the official Nuxt starter template. This command sets up a complete Nuxt project with TypeScript support and all necessary dependencies. Run the following command to [create a new Nuxt application](https://nuxt.com/docs/getting-started/installation): ```bash npm theme={null} npm create nuxt project-name ``` ```bash pnpm theme={null} pnpm create nuxt project-name ``` ```bash bun theme={null} bun create nuxt project-name ``` ```bash yarn theme={null} yarn create nuxt project-name ``` ## Install `@nuxtjs/hanko` Use the `@nuxtjs/hanko` module to integrate Hanko authentication. It provides pre-built components (`hanko-auth`, `hanko-events`, `hanko-profile`), server middleware for route protection, and Vue composables for easy authentication management. Install the module as a development dependency: ```bash npm theme={null} cd project-name npm install -D @nuxtjs/hanko ``` ```bash pnpm theme={null} cd project-name pnpm add -D @nuxtjs/hanko ``` ```bash bun theme={null} cd project-name bun add -D @nuxtjs/hanko ``` ```bash yarn theme={null} cd project-name yarn add --dev @nuxtjs/hanko ``` ## Set up your Hanko project Before integrating Hanko into your application, you need to create a Hanko project in the cloud console. This project will provide you with an API URL and manage your authentication settings. Go to the [Hanko Console](https://cloud.hanko.io/) and [create a project for this application.](/setup-hanko-cloud) During project creation, make sure to set the `APP URL` to your development URL (typically [http://localhost:3000/](http://localhost:3000/)). This ensures proper CORS configuration and redirect handling. ## Add the Hanko API URL After creating your Hanko project, you'll receive a unique API URL. This URL is used to communicate with Hanko's authentication services. The `NUXT_PUBLIC_` prefix makes this environment variable accessible in both server and client-side code. Retrieve the API URL from the [Hanko Console](https://cloud.hanko.io/) and add it to your environment file: ```sh .env theme={null} NUXT_PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` If you are self-hosting you need to provide the URL of your running Hanko backend. ## Configure Nuxt module Next, register the Hanko module in your Nuxt configuration and set up authentication behavior. This configuration defines where users should be redirected after login/logout and sets up the module with your API URL. Add the `@nuxtjs/hanko` module to your `nuxt.config.ts` file: ```jsx nuxt.config.ts theme={null} export default defineNuxtConfig({ modules: ["@nuxtjs/hanko"], hanko: { apiURL: process.env.NUXT_PUBLIC_HANKO_API_URL, cookieName: 'hanko', redirects:{ login: '/',//Path to redirect to when unauthenticated / logged out success: '/dashboard',//Path to redirect to once logged in } }, }) ``` While the module comes pre-configured with the options for most common use cases, you have the flexibility to override them by adding a `hanko` section to your `nuxt.config.ts` file. For all overrides please refer to [module's repository](https://github.com/nuxt-modules/hanko). **Using Hanko Components** You can now use the components anywhere in your app (``, ``, ``). These will render only on client-side and all the props you can pass are strongly typed. If you prefer not to auto-register these components, especially if you plan to use Hanko exclusively on the server side or wish to handle component registration programmatically, you can disable this feature. To do so, set the `registerComponents` option to false in your `nuxt.config.ts` file: ```jsx nuxt.config.ts theme={null} hanko: { registerComponents: false; } ``` ## Setup Nuxt pages Nuxt uses file-based routing, where each file in the `pages/` directory becomes a route. To enable this routing system, add the `NuxtPage` component to your main application template. Update your `app.vue` file to use the Nuxt Page Router: ```vue app.vue theme={null} ``` After that lets create a folder called `/pages` and in there we will create `index.vue` and `dashboard.vue`. ## Add `` component The `` web component provides a complete login and registration interface with passwordless authentication. The `hanko-logged-out` middleware ensures that already authenticated users are automatically redirected to the dashboard. Create your login page at `pages/index.vue`: ```jsx pages/index.vue theme={null} ``` ## Alternative: Custom redirect handling If you need more control over post-login behavior, you can use the `` component to listen for authentication events and implement custom logic. Here's an alternative approach with custom redirect handling: ```jsx pages/index.vue theme={null} ``` ## Define event callbacks Hanko emits various [authentication events](https://github.com/teamhanko/hanko/blob/main/frontend/elements/README.md#events) that you can listen to for custom application logic. These events include session creation, updates, and destruction. Add the `` component to subscribe to authentication events: ```jsx pages/index.vue theme={null} ``` By now, your sign-up and sign-in features should be working. You should see an interface similar to this 👇 sign up ## Add `` The `` component provides a user-friendly interface for managing authentication credentials. Users can add/remove email addresses, register new passkeys, and manage their authentication methods. Create a dashboard page at `pages/dashboard.vue`: ```jsx pages/dashboard.vue theme={null} ``` It should look like this 👇 profile page ## Implement logout functionality To log users out, use the `@nuxtjs/hanko` module's built-in composable `useHanko` and call the `logout` method.
Secure dashboard page that combines profile management with logout functionality, protected by hanko-logged-in middleware and using the useHanko composable for session management
```jsx pages/dashboard.vue theme={null} ``` **useHanko() composable** The `useHanko` composable provides access to the [Hanko SDK](https://docs.hanko.io/jsdoc/hanko-frontend-sdk/index.html) which in turn allows access to the Hanko API, e.g. for accessing the [current user info](https://docs.hanko.io/jsdoc/hanko-frontend-sdk/UserClient.html#getCurrent). The composable is auto-imported across the app and can simply be used with `useHanko()` anywhere in your code. ## Customize component styles You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance). The styles can be scoped to the login/profile page to ensure they dont affect other parts to the app. ## Securing routes with middleware Use the `hanko-logged-in` middleware to secure any route and force unauthenticated users to redirect back to the `login` redirect we set in the `nuxt.config.ts`.
Page metadata configuration that applies the hanko-logged-in middleware to protect routes from unauthorized access
```jsx theme={null} ``` A global server middleware is added by `@nuxtjs/hanko`. After decoding and validating the session token for the request, a new `hanko` property is added to the event context. You can check the value of `event.context.hanko` to see if the request was authenticated. The user's id is accessible though the `sub` claim/property.
Server-side API endpoint example that demonstrates how to access authenticated user information through the event context, with proper error handling for unauthorized requests
```jsx /server/api/endpoint.ts theme={null} export default defineEventHandler(async (event) => { const hanko = event.context.hanko; if (!hanko || !hanko.sub) { return { status: 401, body: { message: "Unauthorized", }, }; } // Do something with the Hanko user return { hanko: event.context.hanko, }; }); ``` ## Try it yourself } > Full source code available on our GitHub # Integrate Hanko with Remix Source: https://docs.hanko.io/quickstarts/fullstack/remix Learn how to quickly add authentication and user profile in your Remix app using Hanko.
**Hanko Fullstack Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This comprehensive guide demonstrates integrating Hanko authentication into your fullstack application using the `@teamhanko/hanko-elements` package. You'll learn to set up authentication components, implement session management, secure routes with middleware, and handle user data across both client and server-side contexts. **Key Technologies**: * Modern fullstack framework with TypeScript, * Server-side rendering capabilities * Hanko Elements * Hanko Cloud Console * Session management * Middleware protection **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen fullstack framework * A Hanko Cloud account (sign up at [https://cloud.hanko.io/signup](https://cloud.hanko.io/signup)) **Integration Tasks You'll Complete**: * Install and configure Hanko Elements package for your framework * Set up HankoAuth component with session event handling and navigation * Create HankoProfile component for user credential management * Implement logout functionality with proper session cleanup and redirects * Secure routes using framework-specific middleware with session validation * Retrieve user data both client-side and server-side using appropriate APIs * Handle authentication redirects, error states, and edge cases * Configure server-side rendering integration and hydration * Customize component appearance and behavior for your application
## Create a Remix application Create a new Remix application using the official starter template. Run the following command to [create a new Remix application](https://remix.run/docs/en/main/start/quickstart): ```bash terminal theme={null} npx create-remix@latest ``` ## Install `@teamhanko/hanko-elements` The Hanko Elements package provides pre-built authentication components (`hanko-auth`, `hanko-profile`) and a JavaScript SDK. Install the package: ```bash npm theme={null} cd project-name npm install @teamhanko/hanko-elements ``` ```bash pnpm theme={null} cd project-name pnpm add @teamhanko/hanko-elements ``` ```bash bun theme={null} cd project-name bun add @teamhanko/hanko-elements ``` ```bash yarn theme={null} cd project-name yarn add @teamhanko/hanko-elements ``` ## Set up your Hanko project Create a Hanko project in the Cloud Console to get your API URL. Go to the [Hanko Console](https://cloud.hanko.io/) and [create a project for this application.](/setup-hanko-cloud) Set the `APP URL` to your development URL (typically [http://localhost:5173/](http://localhost:5173/) for Remix). ## Add the Hanko API URL Add your Hanko API URL to your environment file. In Remix, environment variables without a public prefix are server-side only. Retrieve the API URL from the [Hanko Console](https://cloud.hanko.io/) and add it to your `.env` file: ```sh .env theme={null} HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` If you are self-hosting you need to provide the URL of your running Hanko backend. ## Create client-side utilities The `@teamhanko/hanko-elements` package only works client-side. Use Remix's `.client.ts` file convention to ensure code only runs in the browser. Create a client-side utility file: ```tsx utils/hanko.client.ts theme={null} import { register, Hanko } from "@teamhanko/hanko-elements"; export { register, Hanko }; ``` ## Create Hanko components Create a `components` folder with two files: `HankoAuth.tsx` and `HankoProfile.tsx`. ### Hanko Auth The `HankoAuth` component provides login and registration functionality. It uses Remix's loader to pass the API URL from server to client, and handles the `onSessionCreated` event for post-login navigation. For more information see the [Auth component documentation.](/guides/hanko-elements/auth-component) ```jsx components/HankoAuth.tsx theme={null} import { useNavigate, useLoaderData } from "@remix-run/react"; import { Suspense, useCallback, useEffect, useState } from "react"; import { register, type Hanko } from "../utils/hanko.client"; export const loader = () => { return { hankoUrl: process.env.HANKO_API_URL }; }; const HankoAuth = () => { const [hanko, setHanko] = useState(); const navigate = useNavigate(); const data = useLoaderData(); const hankoUrl = data.hankoUrl || ''; const redirectAfterLogin = useCallback(() => { navigate("/dashboard");//Path user gets navigated to once they log in }, [navigate]); useEffect(() => { if (hanko) { hanko.onSessionCreated(() => { // Successfully Logged In redirectAfterLogin(); }); } }, [hanko, redirectAfterLogin]); useEffect(() => { register(hankoUrl) .catch((error: Error) => { console.error(error.message); }) .then((result) => { if (result) { setHanko(result.hanko); } }); }, [hankoUrl]); return (
); }; export default HankoAuth; ``` ### Hanko Profile The `HankoProfile` component allows users to manage their email addresses and passkeys. For more information see the [Profile component documentation.](/guides/hanko-elements/profile-component) ```jsx components/HankoProfile.tsx theme={null} import { useLoaderData } from "@remix-run/react"; import { Suspense, useEffect, } from "react"; import { register } from "../utils/hanko.client"; export const loader = () => { return { hankoUrl: process.env.HANKO_API_URL }; }; const HankoProfile = () => { const data = useLoaderData(); const hankoUrl = data.hankoUrl || ''; useEffect(() => { register(hankoUrl).catch((error) => { // handle error console.log(error); }); }); return( ) } export default HankoProfile; ``` ## Setup your routes Create your routes in the `/routes` folder. You'll need `_index.tsx` for the login page and `dashboard.tsx` for the user dashboard. Create the main login route: ```jsx routes/_index.tsx theme={null} import HankoAuth from "../components/HankoAuth"; export const loader = () => { return { hankoUrl: process.env.HANKO_API_URL }; }; export default function Index() { return ( <> ); } ``` Create the dashboard route: ```jsx routes/dashboard.tsx theme={null} import HankoProfile from "../components/HankoProfile"; export const loader = () => { return { hankoUrl: process.env.HANKO_API_URL }; }; export default function Dashboard() { return ( <> ); } ``` By now you should be able to go to `/` to see the ``, and to `/dashboard` to see the ``. They should look something like this👇
sign up profile page
If `HankoAuth` is not loading please restart the application as it might've not loaded the .env correctly the first time.\ \ `HankoProfile` will only look like the picture while you are logged in. ## Implement logout functionality Create a logout button using the Hanko SDK's logout method. Create `LogoutButton.tsx`: ```jsx components/LogoutButton.tsx theme={null} import { useLoaderData, useNavigate } from "@remix-run/react"; import { useEffect, useState, } from "react"; import { type Hanko, } from "../utils/hanko.client"; export const loader = () => { return { hankoUrl: process.env.HANKO_API_URL }; }; const LogoutButton = () => { const data = useLoaderData(); const hankoUrl = data.hankoUrl || ''; const navigate = useNavigate(); const [hanko, setHanko] = useState(); useEffect(() => { import("@teamhanko/hanko-elements").then(({ Hanko }) => setHanko(new Hanko(hankoUrl ?? "")) ); }, []); const logout = async () => { try { await hanko?.logout(); navigate("/");//Path the user will be redirected to once logged out return; } catch (error) { console.error("Error during logout:", error); } }; return ; } export default LogoutButton; ``` ## Customize component styles You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance). ## Securing routes Protect routes by validating session tokens in loader functions. Create a server-side authentication utility to handle session validation. Create `app/services/auth.server.ts`: ```jsx app/services/auth.server.ts theme={null} import { parse } from "cookie"; export async function ValidateCurrentSession(request: Request, hankoUrl: string){ const cookies = parse(request.headers.get("Cookie") || ""); const token = cookies.hanko; const validationOptions = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: `{"session_token":"${token}"}` } try { const response = await fetch(hankoUrl + '/sessions/validate', validationOptions); if (!response.ok) throw new Error('Session validation failed'); const verifiedResponse = await response.json(); return verifiedResponse.is_valid } catch (error) { console.log(error) return false; } } ``` Use the authentication service in your protected routes. Update your dashboard route to validate sessions: ```tsx app/routes/dashboard.tsx theme={null} import HankoProfile from "../components/HankoProfile"; import LogoutButton from "../components/LogoutButton"; import { type LoaderFunction, redirect } from "@remix-run/node"; import { ValidateCurrentSession } from "../services/auth.server"; export const loader: LoaderFunction = async ({request}) => { const hankoUrl = process.env.HANKO_API_URL || ""; const validated = await ValidateCurrentSession(request , hankoUrl); if(!validated){ return redirect("/");//Path to redirect to if user is not authenticated } return { hankoUrl: hankoUrl }; }; export default function Dashboard() { return ( <> ); } ``` ## Try it yourself } > Full source code available on our GitHub # Integrate Hanko with SvelteKit Source: https://docs.hanko.io/quickstarts/fullstack/sveltekit Learn how to quickly add authentication and user profile in your SvelteKit app using Hanko.
**Hanko Fullstack Integration Guide**: **About Hanko**: Hanko is a modern open source authentication solution and the fastest way you integrate passkeys, 2FA, SSO, and more—with full control over your data. Move between self-hosted and Hanko Cloud anytime. No lock-in. Just Auth how it should be: secure, user friendly, and fully yours. **What This Guide Covers**: This comprehensive guide demonstrates integrating Hanko authentication into your fullstack application using the `@teamhanko/hanko-elements` package. You'll learn to set up authentication components, implement session management, secure routes with middleware, and handle user data across both client and server-side contexts. **Key Technologies**: * Modern fullstack framework with TypeScript, * Server-side rendering capabilities * Hanko Elements * Hanko Cloud Console * Session management * Middleware protection **Prerequisites**: * Node.js installed on your system * Basic knowledge of your chosen fullstack framework * A Hanko Cloud account (sign up at [https://cloud.hanko.io/signup](https://cloud.hanko.io/signup)) **Integration Tasks You'll Complete**: * Install and configure Hanko Elements package for your framework * Set up HankoAuth component with session event handling and navigation * Create HankoProfile component for user credential management * Implement logout functionality with proper session cleanup and redirects * Secure routes using framework-specific middleware with session validation * Retrieve user data both client-side and server-side using appropriate APIs * Handle authentication redirects, error states, and edge cases * Configure server-side rendering integration and hydration * Customize component appearance and behavior for your application
## Create a SvelteKit application Create a new SvelteKit application using the official SvelteKit starter. Run the following command to [create a new SvelteKit application](https://svelte.dev/docs/kit/creating-a-project): ```bash terminal theme={null} npx sv create project-name ``` ## Install `@teamhanko/hanko-elements` The Hanko Elements package provides pre-built authentication components (`hanko-auth`, `hanko-profile`) that work with Svelte's reactive system. Install the package: ```bash npm theme={null} cd project-name npm install @teamhanko/hanko-elements ``` ```bash pnpm theme={null} cd project-name pnpm add @teamhanko/hanko-elements ``` ```bash bun theme={null} cd project-name bun add @teamhanko/hanko-elements ``` ```bash yarn theme={null} cd project-name yarn add @teamhanko/hanko-elements ``` ## Set up your Hanko project Create a Hanko project in the Cloud Console to get your API URL. Go to the [Hanko Console](https://cloud.hanko.io/) and [create a project for this application.](/setup-hanko-cloud) Set the `APP URL` to your development URL (typically [http://localhost:5173/](http://localhost:5173/) for SvelteKit). ## Add your Hanko API URL Add your Hanko API URL to your environment file. The `PUBLIC_` prefix makes it accessible in both server and client-side code in SvelteKit. Retrieve your API URL from the [Hanko Console](https://cloud.hanko.io/) and add it to your `.env` file: ```sh .env theme={null} PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io ``` If you are self-hosting you need to provide the URL of your running Hanko backend. ## Create Hanko components Create a `components` folder with two files: `HankoAuth.svelte` and `HankoProfile.svelte`. ### Hanko Auth Now let's setup the `HankoAuth.tsx` file to create a functioning login page. Here we subscribe to the `onSessionCreated` [event](/guides/hanko-elements/using-frontend-sdk#events), this triggers when a user successfully logs in. You can use these event to perform any desired action.(e.g. redirect to your dashboard). For more information please refer to the [Auth component page.](/guides/hanko-elements/auth-component)
Svelte authentication component that uses reactive stores, handles session events, and implements navigation to dashboard after successful login
```jsx components/HankoAuth.svelte theme={null} ``` Now simply import the component you just created into any page.
Main page route that imports and renders the HankoAuth component for user login and registration
```jsx routes/+page.svelte theme={null}
``` By now, your sign-up and sign-in features should be working. You should see an interface similar to this 👇 sign up ### Hanko Profile After setting up the HankoAuth let's set up the `HankoProfile.jsx` file to create an interface where users can manage their `Email Addresses` and credentials. For more information please refer to the [Profile component page.](/guides/hanko-elements/profile-component)
Svelte profile component that allows users to manage their email addresses, passkeys, and authentication credentials using Hanko's built-in interface
```jsx components/HankoProfile.svelte theme={null} ``` Now simply import the component you just created into any page.
Protected dashboard page route that imports and displays the HankoProfile component for user account management
```jsx routes/dashboard/+page.svelte theme={null}
``` It should look something like this 👇 profile page ## Implement logout functionality You can use `@teamhanko/hanko-elements` to easily logout users. Here we will make a logout button. Create `LogoutButton.tsx` and insert the code below.
Svelte logout button component that terminates the user session and navigates back to the home page
```jsx components/LogoutButton.svelte theme={null} ``` ## Customize component styles You can customize the appearance of `hanko-auth` and `hanko-profile` components using CSS variables and parts. Refer to our [customization guide](/guides/hanko-elements/customize-appearance). ## Securing routes To verify the session token in your SvelteKit application, we're using the [session/validate API request](/api-reference/public/session-management/validate-a-session). By checking for a valid session token this middleware will ensure secure access to specific routes, like `/dashboard` and `/protected`.\ The middleware hook extracts and verifies the session token, and redirect unauthorized users back to the home or login page. For more info on middlewares / hooks in SvelteKit and where to put the `hooks.server.ts` file,\ please refer to [SvelteKit Hooks](https://svelte.dev/docs/kit/hooks). What happens here is that during each request the handle function will be called. It then verifies the session token and redirects the user back if he is on a private route and the session token is not valid. Hooks like these tends to not always work after creating it, if this is the case try restarting your SvelteKit app.
SvelteKit server hooks that implement route protection by validating session tokens and redirecting unauthorized users away from protected routes
```tsx hooks.server.ts theme={null} import { type RequestEvent, redirect, type Handle } from "@sveltejs/kit"; import { env } from "$env/dynamic/public"; const hankoApiUrl = env.PUBLIC_HANKO_API_URL; export const handle: Handle = async ({ event, resolve }) => { const verified = await authenticatedUser(event); if (event.url.pathname.startsWith("/dashboard") && !verified) { throw redirect(303, "/"); } if (event.url.pathname.startsWith("/profile") && !verified) { throw redirect(303, "/"); } const response = await resolve(event); return response; }; const authenticatedUser = async (event: RequestEvent) => { const { cookies } = event; const cookieToken = cookies.get("hanko"); const validationOptions = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: `{"session_token":"${cookieToken}"}` } try { const response = await fetch(hankoApiUrl + '/sessions/validate', validationOptions); if (!response.ok) throw new Error('Session validation failed'); const verifiedResponse = await response.json(); console.log(verifiedResponse) return verifiedResponse.is_valid; } catch (error) { console.log(error) return false; } }; ``` ## Getting user data Let's use the Hanko SDK to get user data. Let's update the `dashboard` page to display some of the information from the user.
Enhanced dashboard page that retrieves and displays user data (email and ID) using the Hanko SDK alongside the profile management component
```jsx routes/dashboard/+page.svelte theme={null}

{email}

{id}

``` ## Try out yourself } > Full source code available on our GitHub # Hanko quickstart guides Source: https://docs.hanko.io/quickstarts/overview Select your framework or programming language below to open the quickstart guide for it. ## Full stack } href="/quickstarts/fullstack/next" /> } href="/quickstarts/fullstack/nuxt" /> } href="/quickstarts/fullstack/remix" /> } href="/quickstarts/fullstack/sveltekit" /> ## Frontend } href="/quickstarts/frontend/angular" /> } href="/quickstarts/frontend/javascript" /> } href="/quickstarts/frontend/react" /> } href="/quickstarts/frontend/solid" /> } href="/quickstarts/frontend/svelte" /> } href="/quickstarts/frontend/vue" /> ## Backend } href="/quickstarts/backend/go" /> } href="/quickstarts/backend/javascript" /> } href="/quickstarts/backend/java_spring" /> } href="/quickstarts/backend/python" /> } href="/quickstarts/backend/rust" /> # Examples Source: https://docs.hanko.io/resources/examples Example apps showcasing integration of Hanko with your favorite frameworks } > Full source code available on our GitHub. } > Full source code available on our GitHub. } > Full source code available on our GitHub. } > Full source code available on our GitHub } > Full source code available on our GitHub. } > Full source code available on our GitHub. } > Full source code available on our GitHub. } > Full source code available on our GitHub. } > Full source code available on our GitHub } > Full source code available on our GitHub } > Full source code available on our GitHub } > Full source code available on our GitHub. # Frontend SDK Source: https://docs.hanko.io/resources/frontend-sdk # Getting started with Hanko Cloud Source: https://docs.hanko.io/setup-hanko-cloud This guide walks you through setting up your Hanko Cloud project and obtaining your API key to integrate Hanko into your app. When using Hanko for your app's authentication, the easiest way is to do that is by utilizing Hanko Cloud infrastructure where we host the Hanko backend for you. You can set up and manage your Hanko projects via the Hanko Cloud Console. Here's a quick video guide to get started with Hanko Cloud: