docs: add mfa login docs (u2f, totp, sms, email) (#6456)

* docs: add mfa login docs (u2f, totp)

* docs: add sms otp registration

* docs: add required in the proto docs

* docs: authenticate with sms code

* docs: authenticate with email code

* docs: fix email code part

* docs: add otp email/sms to self service

* docs: secret generator naming

* docs: fix docs

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Fabi 2023-09-08 13:28:40 +02:00 committed by GitHub
parent 856d0d12e8
commit aca5de8e40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 409 additions and 46 deletions

View File

@ -151,7 +151,9 @@ The current password must be entered first.
Users can setup and delete a second factor and FIDO Passkeys (Passwordless).
Available authenticators are:
- Mobile one-time password (OTP) (Authenticator Apps)
- Time-based one-time password (TOTP) (Which are Authenticator Apps like Google/Microsoft Authenticator, Authy, etc.)
- One-time password sent as E-Mail
- One-time password sent as SMS
- FIDO Universal Second Factor (U2F) (Security Keys, Device, etc.)
- FIDO2 WebAuthN (Passkeys)

View File

@ -0,0 +1,12 @@
After starting the WebAuthN 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.
```javascript
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".

View File

@ -0,0 +1,25 @@
Now that you have successfully authenticated in the browser, you can update the session of the user.
Fill the webAuthN 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": {
"webAuthN": {
"credentialAssertionData": {}
}
}
}'
```

View File

@ -5,13 +5,17 @@ sidebar_label: Multi-Factor (MFA)
import MfaOptions from './_list-mfa-options.mdx';
import BrowserRegisterWebAuthN from './_browser_register_webauthn.mdx';
import BrowserSigninWebAuthN from './_browser_signin_webauthn.mdx';
import UpdateSessionWebAuthN from './_update_session_webauthn.mdx';
Multi-factor authentication (MFA) is a multi-step account authentication which requires to user to enter more than only the password.
It is highly recommended to use MFA or [Passkeys](./passkey) to make your user accounts more secure.
ZITADEL supports two different Methods:
ZITADEL supports different Methods:
- Time-based one time password (TOTP), which are Authenticator apps like Google/Microsoft Authenticator, Authy, etc
- One-time password sent as SMS
- One-time password sent as E-Mail
- Universal Second Factor (U2F), which is authentication with your device like Windows Hello, Apple FaceID, Fingerprint, FIDO2 keys, Yubikey, etc.
## TOTP Registration
@ -78,6 +82,292 @@ curl --request POST \
}'
```
## TOTP Authentication
### Flow
![Authenticate TOTP](/img/guides/login-ui/authenticate-totp-flow.png)
### Check User
To be able to check the TOTP you need a session with a checked user. This can either happen before the TOTP check or at the same time.
In this example we do two separate requests. So the first step is to create a new Sessions.
More detailed information about the API: [Create new session Documentation](/apis/resources/session_service/session-service-create-session)
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": "minnie-mouse@mouse.com"
}
}
}'
```
Example Response
```bash
{
"details": {
"sequence": "580",
"changeDate": "2023-06-14T05:32:39.007096Z",
"resourceOwner": "163840776835432705"
},
"sessionId": "218480890961985793",
"sessionToken": "yMDi6uVPJAcphbbz0LaxC07ihWkNTe7m0Xqch8SzfM5Cz3HSIQIDZ65x1f5Qal0jxz0MEyo-_zYcUg"
}
```
### Check TOTP
Now you can show the code field to the user, where he has to enter the code from the Authenticator App.
With that code you have to update the existing session with a totp check.
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/$SESSION-ID \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"sessionToken": "W3mEoesTiYOsiR1LYUCRw3vaEwXKLGDTsqOV_bkOhlah_-ZbuiLgvnzADwe_iYMusbwkMhp7VfMn8j",
"checks": {
"totp": {
"code": "323764"
},
}
}'
```
## SMS Code Registration
### Flow
![Register SMS OTP](/img/guides/login-ui/register-phone-otp-flow.png)
### List the Possible Methods
<MfaOptions/>
### Add Phone Number
When the user has decided to register the phone number to get a code as a second factor, the first step is to add a verified phone number to the user.
If the user already has a verified phone number you can skip this step.
When adding a new phone number, you can choose if you want ZITADEL to send the verification code to the number, or if you want to send it by yourself.
If ZITADEL should do it, make sure that you have registered an [SMS Provider](/docs/guides/manage/console/instance-settings#sms) and send an empty sendCode object in the request.
With an empty returnCode object in the request, ZITADEL will not send the code, but return it in the response.
If you don't want the user to verify the phone number, you can also create it directly as verified, by sending the isVerified attribute.
More detailed information about the API: [Add phone](/apis/resources/user_service/user-service-set-phone)
Example Request:
```bash
curl --request POST \
--url https://$ZITADEL_DOMAIN/v2alpha/users/$USER-ID/phone \
--header 'Accept: application/json' \
--header 'Authorization: Bearer '"$TOKEN"'' \
--header 'Content-Type: application/json' \
--data '{
"phone": "+41791234567",
"sendCode": {}
}'
```
### Verify Phone Number
The next step is to show a screen, so the user is able to enter the code for verifying the phone number.
Send a verify phone request with the code in the body.
More detailed information about the API: [Verify phone](/apis/resources/user_service/user-service-verify-phone)
Example Request:
```bash
curl --request POST \
--url https://$ZITADEL_DOMAIN/v2alpha/users/$USER-ID/phone/verify \
--header 'Accept: application/json' \
--header 'Authorization: Bearer '"$TOKEN"'' \
--header 'Content-Type: application/json' \
--data '{
"verificationCode": "VBQREB"
}'
```
### Add OTP SMS to the user
Now that the user has a verified phone number you can enable SMS OTP on the user.
More detailed information about the API: [Add OTP SMS for a user](/apis/resources/user_service/user-service-add-otpsms)
Example Request:
```bash
curl --request POST \
--url https://$ZITADEL_DOMAIN/v2alpha/users/$USER-ID/otp_sms \
--header 'Accept: application/json' \
--header 'Authorization: Bearer '"$TOKEN"'' \
--header 'Content-Type: application/json'
```
## SMS Code Authentication
### Flow
![Authenticate SMS OTP](/img/guides/login-ui/authenticate-phone-otp-flow.png)
### Check User
To be able to check the SMS Code you need a session with a checked user.
When creating the session you can already start the sms challenge, this will only be executed if the user check was successful.
You can tell the challenge, if the code should be returned (returnCode: true) or if ZITADEL should send it (returnCode: false).
More detailed information about the API: [Create new session Documentation](/apis/resources/session_service/session-service-create-session)
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"
}
},
"challenges": {
"otpSms": {
"returnCode": false
}
}
}'
```
### Check SMS Code
In the next step you should show the user a code field, where he can enter the code, he got as SMS.
The update session request has a check otpSMS where you should send the code, the user has entered.
Example Request
```bash
curl --request PATCH \
--url https://$ZITADEL_DOMAIN/v2alpha/sessions/225307381909694507 \
--header 'Accept: application/json' \
--header 'Authorization: Bearer '"$TOKEN"'' \
--header 'Content-Type: application/json' \
--data '{
"sessionToken": "W3mEoesTiYOsiR1LYUCRw3WaFwXKLGDRsqOV_bkOhlah_-ZpuiLgvnzADwe_iYMusbwkMhp7VfMn8g",
"checks": {
"otpSms": {
"code": "3237642"
},
}
}'
```
## Email Code Registration
### Flow
![Register Email OTP](/img/guides/login-ui/register-email-otp-flow.png)
### List the Possible Methods
<MfaOptions/>
### Verified Email
As ZITADEL required all users to have a verified email address, you do not need to add a new email and verify it for setting up the second factor.
For the Email second factor the already verified email address will be taken.
### Add OTP Email to the user
As the user already has a verified E-Mail address you can enable E-Mail OTP on the user.
More detailed information about the API: [Add OTP Email for a user](/apis/resources/user_service/user-service-add-otp-email)
Example Request:
```bash
curl --request POST \
--url https://$ZITADEL_DOMAIN/v2alpha/users/$USER-ID/otp_email \
--header 'Accept: application/json' \
--header 'Authorization: Bearer '"$TOKEN"'' \
--header 'Content-Type: application/json'
```
## Email Code Authentication
### Flow
![Authenticate OTP Email](/img/guides/login-ui/authenticate-email-otp-flow.png)
### Check User
To be able to check the Email Code you need a session with a checked user.
When creating the session you can already start the sms challenge, this will only be executed if the user check was successful.
You can tell the challenge, if the code should be returned (returnCode: true) or if ZITADEL should send it (returnCode: false).
More detailed information about the API: [Create new session Documentation](/apis/resources/session_service/session-service-create-session)
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"
}
},
"challenges": {
"otpEmail": {
"returnCode": false
}
}
}'
```
### Check Email Code
In the next step you should show the user a code field, where he can enter the code, he got per E-Mail.
The update session request has a check otpEmail where you should send the code, the user has entered.
Example Request
```bash
curl --request PATCH \
--url https://$ZITADEL_DOMAIN/v2alpha/sessions/225307381909694507 \
--header 'Accept: application/json' \
--header 'Authorization: Bearer '"$TOKEN"'' \
--header 'Content-Type: application/json' \
--data '{
"sessionToken": "W3mEoesTiYOsiR1LYUCRw3WaFwXKLGDRsqOV_bkOhlah_-ZpuiLgvnzADwe_iYMusbwkMhp7VfMn8g",
"checks": {
"otpEmail": {
"code": "3237642"
},
}
}'
```
## U2F Registration
### Flow
@ -181,7 +471,7 @@ curl --request POST \
"rawId": "pawVarF4xPxLFmfCnRkwXWeTrKGzabcAi92LEI1WC00",
"response": {
"attestationObject": "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIgRKS3VpeE9tfExXRzkoUKnG4rQWPvtSSt4YtDGgTx32oCIQDPey-2YJ4uIg-QCM4jj6aE2U3tgMFM_RP7Efx6xRu3JGhhdXRoRGF0YVikSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAADju76085Yhmlt1CEOHkwLQAIKWsFWqxeMT8SxZnwp0ZMF1nk6yhs2m3AIvdixCNVgtNpQECAyYgASFYIMGUDSP2FAQn2MIfPMy7cyB_Y30VqixVgGULTBtFjfRiIlggjUGfQo3_-CrMmH3S-ZQkFKWKnNBQEAMkFtG-9A4zqW0",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiQlhXdHh0WGxJeFZZa0pHT1dVaUVmM25zby02aXZKdWw2YmNmWHdMVlFIayIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0OjgwODAifQ"
"clientDataJSON": "eyJ0eXBlJjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiQlhXdHh0WGxJeFZZa0pHT1dVaUVmM25zby02aXZKdWw2YmNmWHdMVlFIayIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0OjgwODAifQ"
}
},
"tokenName": "Google Pixel"
@ -189,3 +479,65 @@ curl --request POST \
```
You have successfully registered a new U2F to the user.
## U2F Authentication
### Flow
![Authenticate U2F](/img/guides/login-ui/authenticate-u2f-flow.png)
### Check User
To be able to check the Universal-Second-Factor (U2F) you need a user check and a webAuthN challenge.
In the creat session request you can check for the user and directly initiate the webAuthN challenge.
For U2F you can choose between "USER_VERIFICATION_REQUIREMENT_PREFERRED" and "USER_VERIFICATION_REQUIREMENT_DISCOURAGED" for the challenge.
Best practice is using discouraged, as this doesn't require the user to enter a PIN. With `preferred` the user might be prompted for the PIN, but it is not necessary.
More detailed information about the API: [Create new session Documentation](/apis/resources/session_service/session-service-create-session)
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": {
"webAuthN": {
"domain": "YOUR-Domain",
"userVerificationRequirement": "USER_VERIFICATION_REQUIREMENT_DISCOURAGED"
}
}
}'
```
Example Response
```bash
{
"details": {
"sequence": "580",
"changeDate": "2023-06-14T05:32:39.007096Z",
"resourceOwner": "163840776835432705"
},
"sessionId": "218480890961985793",
"sessionToken": "yMDi6uVPJAcphbbz0LaxC07ihWkNTe7m0Xqch8SzfM5Cz3HSIQIDZ65x1f5Qal0jxz0MEyo-_zYcUg"
}
```
### Signin in Browser
<BrowserSigninWebAuthN/>
### Update Session with WebAuthN
<UpdateSessionWebAuthN/>

View File

@ -3,6 +3,10 @@ title: Passkeys
sidebar_label: Passkeys
---
import BrowserRegisterWebAuthN from './_browser_register_webauthn.mdx';
import BrowserSigninWebAuthN from './_browser_signin_webauthn.mdx';
import UpdateSessionWebAuthN from './_update_session_webauthn.mdx';
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/) .
@ -208,7 +212,6 @@ Next step is to authenticate the user with the new registered passkey.
![Passkey Login](/img/guides/login-ui/passkey-login-flow.png)
### Create Session
First step is to ask the user for his username and create a new session with the ZITADEL API.
@ -273,43 +276,11 @@ Example Response:
### 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.
<BrowserSigninWebAuthN/>
```javascript
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": {
"webAuthN": {
"credentialAssertionData": {}
}
}
}'
```
### Update Session with WebAuthN
<UpdateSessionWebAuthN/>

View File

@ -81,8 +81,8 @@ Return Code:
To check what is allowed on your instance, call the settings service for more information.
The following requests can be useful for registration:
- [Get Login Settings](https://zitadel.com/docs/apis/resources/settings_service/settings-service-get-login-settings) To find out which authentication possibilities are enabled (password, identity provider, etc.)
- [Get Password Complexity Settings](https://zitadel.com/docs/apis/resources/settings_service/settings-service-get-password-complexity-settings) to find out how the password should look like (length, characters, etc.)
- [Get Login Settings](/apis/resources/settings_service/settings-service-get-login-settings) To find out which authentication possibilities are enabled (password, identity provider, etc.)
- [Get Password Complexity Settings](/apis/resources/settings_service/settings-service-get-password-complexity-settings) to find out how the password should look like (length, characters, etc.)
## Create Session with User Check
@ -96,9 +96,9 @@ The create and update session endpoints will always return a session ID and an o
If you do not rely on the OIDC standard you can directly use the token.
Send it to the Get Session Endpoint to find out how the user has authenticated.
- [Create new session Documentation](https://zitadel.com/docs/apis/resources/session_service/session-service-create-session)
- [Update an existing session Documentation](https://zitadel.com/docs/apis/resources/session_service/session-service-set-session)
- [Get Session Documentation](https://zitadel.com/docs/apis/resources/session_service/session-service-get-session)
- [Create new session Documentation](/apis/resources/session_service/session-service-create-session)
- [Update an existing session Documentation](/apis/resources/session_service/session-service-set-session)
- [Get Session Documentation](/apis/resources/session_service/session-service-get-session)
### Request

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

View File

@ -8006,6 +8006,7 @@ message UpdateHumanProfileRequest {
];
string display_name = 5 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;

View File

@ -202,8 +202,8 @@ service UserService {
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Change the user phone";
description: "Change the phone number of a user. If the state is set to not verified, a verification code will be generated, which can be either returned or sent to the user by sms."
summary: "Set the user phone";
description: "Set the phone number of a user. If the state is set to not verified, a verification code will be generated, which can be either returned or sent to the user by sms."
responses: {
key: "200"
value: {