mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:07:36 +00:00
docs: Passkey (#6110)
* docs: add docs for passkey registration and login * docs: add docs for passkey registration and login * docs: passkey registration * docs: add passkey guide to sidenav * docs: passkey guide * docs: passkey flow * Update docs/docs/guides/integrate/login-ui/passkey.mdx Co-authored-by: Florian Forster <florian@zitadel.com> * Update docs/docs/guides/integrate/login-ui/passkey.mdx Co-authored-by: Florian Forster <florian@zitadel.com> * Update docs/docs/guides/integrate/login-ui/passkey.mdx Co-authored-by: Florian Forster <florian@zitadel.com> * Update docs/docs/guides/integrate/login-ui/passkey.mdx Co-authored-by: Florian Forster <florian@zitadel.com> * Update docs/docs/guides/integrate/login-ui/passkey.mdx Co-authored-by: Florian Forster <florian@zitadel.com> * Update docs/docs/guides/integrate/login-ui/passkey.mdx * Update docs/docs/guides/integrate/login-ui/passkey.mdx Co-authored-by: Florian Forster <florian@zitadel.com> * docs: passkey flow * docs: passkey flow * docs: passkeys --------- Co-authored-by: Florian Forster <florian@zitadel.com>
This commit is contained in:
324
docs/docs/guides/integrate/login-ui/passkey.mdx
Normal file
324
docs/docs/guides/integrate/login-ui/passkey.mdx
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
---
|
||||||
|
title: Passkeys
|
||||||
|
sidebar_label: Passkeys
|
||||||
|
---
|
||||||
|
|
||||||
|
Passkeys are a replacement for passwords that provide faster, easier, and more secure sign-ins to websites and apps even across multiple devices.
|
||||||
|
Unlike passwords, passkeys are phishing-resistant and can improve the user experience and security at the same time.
|
||||||
|
Passkeys and there underlying protocols are a standard defined by the [FIDO Standard](https://fidoalliance.org/) .
|
||||||
|
|
||||||
|
## Register Passkey
|
||||||
|
|
||||||
|
### Flow
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Request Example:
|
||||||
|
Send either the sendLink or the returnCode (empty message) in the request body, depending on the use case you have.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --request POST \
|
||||||
|
--url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/passkeys/registration_link \
|
||||||
|
--header 'Accept: application/json' \
|
||||||
|
--header 'Authorization: Bearer '"$TOKEN"''\
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"sendLink": {
|
||||||
|
"urlTemplate": "https://example.com/passkey/register?userID={{.UserID}}&orgID={{.OrgID}}&codeID={{.CodeID}}&code={{.Code}}"
|
||||||
|
},
|
||||||
|
"returnCode": {}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response Example:
|
||||||
|
The code is only filled if returnCode has been requested in the Request.Passkey
|
||||||
|
|
||||||
|
```bash
|
||||||
|
{
|
||||||
|
"details": {
|
||||||
|
"sequence": "632",
|
||||||
|
"changeDate": "2023-06-28T08:09:51.257699Z",
|
||||||
|
"resourceOwner": "163840776835432705"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"id": "220526087715684609",
|
||||||
|
"code": "2KEpIeQGSBBd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Start Passkey Registration
|
||||||
|
|
||||||
|
When starting the passkey registration you can optionally send the registration code from the step above to ZITADEL to pair it with a specific user.
|
||||||
|
|
||||||
|
By specifying the authenticator type you can choose if the passkey should be cross platform or not. Per default all types are allowed:
|
||||||
|
- PASSKEY_AUTHENTICATOR_UNSPECIFIED
|
||||||
|
- PASSKEY_AUTHENTICATOR_PLATFORM
|
||||||
|
- PASSKEY_AUTHENTICATOR_CROSS_PLATFORM
|
||||||
|
|
||||||
|
The API response will provide you the public key credential options, this will be used by the browser to obtain a signed challenge.
|
||||||
|
|
||||||
|
More detailed information about the API: [Start Passkey Registration Documentation](/apis/resources/user_service/user-service-register-passkey)
|
||||||
|
|
||||||
|
Request Example:
|
||||||
|
The code only has to be filled if the user did get a registration code.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --request POST \
|
||||||
|
--url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/passkeys \
|
||||||
|
--header 'Accept: application/json' \
|
||||||
|
--header 'Authorization: Bearer '"$TOKEN"''\
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"code": {
|
||||||
|
"id": "220526087715684609",
|
||||||
|
"code": "2KEpIeQGSBBd"
|
||||||
|
},
|
||||||
|
"authenticator": "PASSKEY_AUTHENTICATOR_UNSPECIFIED"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
{
|
||||||
|
"details": {
|
||||||
|
"sequence": "633",
|
||||||
|
"changeDate": "2023-06-28T08:10:26.725981Z",
|
||||||
|
"resourceOwner": "163840776835432705"
|
||||||
|
},
|
||||||
|
"passkeyId": "220526147258024193",
|
||||||
|
"publicKeyCredentialCreationOptions": {
|
||||||
|
"publicKey": {
|
||||||
|
"attestation": "none",
|
||||||
|
"authenticatorSelection": {
|
||||||
|
"userVerification": "required"
|
||||||
|
},
|
||||||
|
"challenge": "JM1uLbVQR2xZJ210DA7E-3j0Cd9rHKUSmc8NyIJBtAY",
|
||||||
|
"pubKeyCredParams": [
|
||||||
|
{
|
||||||
|
"alg": -7,
|
||||||
|
"type": "public-key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": -35,
|
||||||
|
"type": "public-key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": -36,
|
||||||
|
"type": "public-key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": -257,
|
||||||
|
"type": "public-key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": -258,
|
||||||
|
"type": "public-key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": -259,
|
||||||
|
"type": "public-key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": -37,
|
||||||
|
"type": "public-key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": -38,
|
||||||
|
"type": "public-key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": -39,
|
||||||
|
"type": "public-key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alg": -8,
|
||||||
|
"type": "public-key"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rp": {
|
||||||
|
"id": "example.domain.com",
|
||||||
|
"name": "ZITADEL"
|
||||||
|
},
|
||||||
|
"timeout": 300000,
|
||||||
|
"user": {
|
||||||
|
"displayName": "Minnie Mouse",
|
||||||
|
"id": "MjE4NjYyNTk2OTE4NjQwODk3",
|
||||||
|
"name": "minni-mouse@mouse.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Register new Passkey on current device
|
||||||
|
|
||||||
|
Now that you have started the registration within ZITADEL, you have to register the credentials in the browser.
|
||||||
|
This requires a call to the browser api and looks something like the following.
|
||||||
|
Make sure to send the public key credential creation options you got in the previous request from ZITADEL.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
const credential = await navigator.credentials.create({
|
||||||
|
publicKey: publicKeyCredentialCreationOptions
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information about WebAuthN and registering credential flow, read the following guide:
|
||||||
|
[Registering a WebAuthN Credentials](https://webauthn.guide/#registration)
|
||||||
|
|
||||||
|
### Verify Passkey in ZITADEL
|
||||||
|
|
||||||
|
In the next request you have to verify the Passkey within ZITADEL.
|
||||||
|
Include the public key credential you got from the browser in your request.
|
||||||
|
You can give the Passkey a name, which makes it easier for the user to identify the registered authentication methods.
|
||||||
|
Example: Google Pixel, iCloud Keychain, Yubikey, etc
|
||||||
|
|
||||||
|
More detailed information about the API: [Verify Passkey Registration Documentation](/apis/resources/user_service/user-service-verify-passkey-registration)
|
||||||
|
|
||||||
|
Example Request:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --request POST \
|
||||||
|
--url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/passkeys/$PASSKEY_ID \
|
||||||
|
--header 'Accept: application/json' \
|
||||||
|
--header 'Authorization: Bearer '"$TOKEN"''\
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"publicKeyCredential": {
|
||||||
|
"type": "public-key",
|
||||||
|
"id": "pawVarF4xPxLFmfCnRkwXWeTrKGzabcAi92LEI1WC00",
|
||||||
|
"rawId": "pawVarF4xPxLFmfCnRkwXWeTrKGzabcAi92LEI1WC00",
|
||||||
|
"response": {
|
||||||
|
"attestationObject": "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgRKS3VpeE9tfExXRzkoUKnG4rQWPvtSSt4YtDGgTx32oCIQDPey-2YJ4uIg-QCM4jj6aE2U3tgMFM_RP7Efx6xRu3JGhhdXRoRGF0YVikSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAADju76085Yhmlt1CEOHkwLQAIKWsFWqxeMT8SxZnwp0ZMF1nk6yhs2m3AIvdixCNVgtNpQECAyYgASFYIMGUDSP2FAQn2MIfPMy7cyB_Y30VqixVgGULTBtFjfRiIlggjUGfQo3_-CrMmH3S-ZQkFKWKnNBQEAMkFtG-9A4zqW0",
|
||||||
|
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiQlhXdHh0WGxJeFZZa0pHT1dVaUVmM25zby02aXZKdWw2YmNmWHdMVlFIayIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0OjgwODAifQ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"passkeyName": "Google Pixel"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
You have successfully registered a new passkey to the user.
|
||||||
|
Next step is to authenticate the user with the new registered passkey.
|
||||||
|
|
||||||
|
## Login with Passkey
|
||||||
|
|
||||||
|
### Flow
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Example Request:
|
||||||
|
```bash
|
||||||
|
curl --request POST \
|
||||||
|
--url https://$ZITADEL_DOMAIN/v2alpha/sessions \
|
||||||
|
--header 'Accept: application/json' \
|
||||||
|
--header 'Authorization: Bearer '"$TOKEN"''\
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"checks": {
|
||||||
|
"user": {
|
||||||
|
"loginName": "minni-mouse@mouse.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"challenges": [
|
||||||
|
"CHALLENGE_KIND_PASSKEY"
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Example Response:
|
||||||
|
```bash
|
||||||
|
{
|
||||||
|
"details": {
|
||||||
|
"sequence": "2",
|
||||||
|
"changeDate": "2023-06-27",
|
||||||
|
"resourceOwner": "69629023906488334"
|
||||||
|
},
|
||||||
|
"sessionId": "d654e6ba-70a3-48ef-a95d-37c8d8a7901a",
|
||||||
|
"sessionToken": "string",
|
||||||
|
"challenges": {
|
||||||
|
"passkey": {
|
||||||
|
"publicKeyCredentialRequestOptions": {
|
||||||
|
"publicKey": {
|
||||||
|
"allowCredentials": [
|
||||||
|
{
|
||||||
|
"id": "ATmqBg-99qyOZk2zloPdJQyS2R7IkFT7v9Hoos_B_nM",
|
||||||
|
"type": "public-key"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"challenge": "GAOHYz2jE69kJMYo6Laij8yWw9-dKKgbViNhfuy0StA",
|
||||||
|
"rpId": "example.domain.com",
|
||||||
|
"timeout": 300000,
|
||||||
|
"userVerification": "required"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Signing in Browser
|
||||||
|
|
||||||
|
After starting the passkey authentication on the side of ZITADEL you have to challenge the browser.
|
||||||
|
To do this you need to call the browser API to get the credentials.
|
||||||
|
Make sure to send the public key credential request options you got from ZITADEL.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
const credential = await navigator.credentials.get({
|
||||||
|
publicKey: publicKeyCredentialRequestOptions
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Read the [WebAuthN Guide](https://webauthn.guide/#authentication) for more information about "Authenticating with a WebAuthN Credential".
|
||||||
|
|
||||||
|
### Update Session with Passkey
|
||||||
|
|
||||||
|
Now that you have successfully authenticated in the browser, you can update the session of the user.
|
||||||
|
Fill the passkey checks with the credential assertion data you get from the browser.
|
||||||
|
|
||||||
|
More detailed information about the API: [Update Session Documentation](/apis/resources/session_service/session-service-set-session)
|
||||||
|
|
||||||
|
Example Request:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --request PATCH \
|
||||||
|
--url https://$ZITADEL_DOMAIN/v2alpha/sessions/218480890961985793 \
|
||||||
|
--header 'Accept: application/json' \
|
||||||
|
--header 'Authorization: Bearer '"$TOKEN"''\
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"sessionToken": "yMDi6uVPJAcphbbz0LaxC07ihWkNTe7m0Xqch8SzfM5Cz3HSIQIDZ65x1f5Qal0jxz0MEyo-_zYcUg",
|
||||||
|
"checks": {
|
||||||
|
"passkey": {
|
||||||
|
"credentialAssertionData": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -15,6 +15,8 @@ The goal is to send the user a verification code, which he can use to verify the
|
|||||||
|
|
||||||
There are two possible ways: You can either let ZITADEL send the notification with the verification code, or you can ask ZITADEL for returning the code and send the email by yourself.
|
There are two possible ways: You can either let ZITADEL send the notification with the verification code, or you can ask ZITADEL for returning the code and send the email by yourself.
|
||||||
|
|
||||||
|
[Request Password Reset Documentation](/apis/resources/user_service/user-service-password-reset)
|
||||||
|
|
||||||
### ZITADEL sends the verification message
|
### ZITADEL sends the verification message
|
||||||
|
|
||||||
When you want ZITADEL to send the verification code you can define the notification channel.
|
When you want ZITADEL to send the verification code you can define the notification channel.
|
||||||
@@ -22,7 +24,6 @@ Per default the verification code will be sent to the email address of the user.
|
|||||||
|
|
||||||
Make sure to also include the URL Template to customize the reset link in the email sent to the user.
|
Make sure to also include the URL Template to customize the reset link in the email sent to the user.
|
||||||
|
|
||||||
|
|
||||||
### Request
|
### Request
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -82,6 +83,8 @@ From a user experience perspective it is nice to prefill the verification code,
|
|||||||
As soon as the user has typed the new password, you can send the change password request.
|
As soon as the user has typed the new password, you can send the change password request.
|
||||||
The change password request allows you to set a new password for the user.
|
The change password request allows you to set a new password for the user.
|
||||||
|
|
||||||
|
[Change Password Documentation](/apis/resources/user_service/user-service-set-password)
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
This request can be used in the password reset flow as well as to let your user change the password manually.
|
This request can be used in the password reset flow as well as to let your user change the password manually.
|
||||||
In this case it requires additionally the current password instead of the verification code.
|
In this case it requires additionally the current password instead of the verification code.
|
||||||
|
@@ -182,6 +182,7 @@ module.exports = {
|
|||||||
items: [
|
items: [
|
||||||
"guides/integrate/login-ui/username-password",
|
"guides/integrate/login-ui/username-password",
|
||||||
"guides/integrate/login-ui/external-login",
|
"guides/integrate/login-ui/external-login",
|
||||||
|
"guides/integrate/login-ui/passkey",
|
||||||
"guides/integrate/login-ui/select-account",
|
"guides/integrate/login-ui/select-account",
|
||||||
"guides/integrate/login-ui/password-reset",
|
"guides/integrate/login-ui/password-reset",
|
||||||
"guides/integrate/login-ui/logout",
|
"guides/integrate/login-ui/logout",
|
||||||
|
BIN
docs/static/img/guides/login-ui/passkey-login-flow.png
vendored
Normal file
BIN
docs/static/img/guides/login-ui/passkey-login-flow.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 251 KiB |
BIN
docs/static/img/guides/login-ui/passkey-registration-flow.png
vendored
Normal file
BIN
docs/static/img/guides/login-ui/passkey-registration-flow.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 241 KiB |
Reference in New Issue
Block a user