diff --git a/docs/docs/guides/integrate/login-ui/_logout.mdx b/docs/docs/guides/integrate/login-ui/_logout.mdx new file mode 100644 index 000000000..9ed441466 --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/_logout.mdx @@ -0,0 +1,20 @@ +When your user is done using your application and clicks on the logout button, you have to send a request to the terminate session endpoint. +[Terminate Session Documentation](https://zitadel.com/docs/apis/resources/session_service/session-service-delete-session) + +Send the session token in the body of the request. + +### Request + +```bash +curl --request DELETE \ + --url https://$ZITADEL_DOMAIN/v2alpha/sessions/218480890961985793 \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "sessionToken": "blGKerGQPKv8jN21p6E9GB1B-vl6_EyKlvTd5UALu8-aQmjucgZxHSXJx3XMFTwT9_Y3VnbOo3gC_Q" +}' +``` + +Terminating a session means to delete it. +If you try to read the session afterwards, you will get an error “Session does not exist”. diff --git a/docs/docs/guides/integrate/login-ui/_select-account.mdx b/docs/docs/guides/integrate/login-ui/_select-account.mdx new file mode 100644 index 000000000..7bf31174c --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/_select-account.mdx @@ -0,0 +1,80 @@ + +If you want to build your own select account/account picker, you have to cache the session IDs. +We recommend storing a list of the session Ids with the corresponding session token in a cookie. +The list of session IDs can be sent in the “search sessions” request to get a detailed list of sessions for the account selection. + +[Search Sessions Documentation](https://zitadel.com/docs/apis/resources/session_service/session-service-list-sessions) + +### Request + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/sessions/_search \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "query": { + "offset": "0", + "limit": 100, + "asc": true + }, + "queries": [ + { + "idsQuery": { + "ids": [ + "218380657934467329", "218480890961985793" + ] + } + } + ] +}' +``` + +### Response + +```bash +{ + "details": { + "totalResult": "2", + "processedSequence": "582", + "timestamp": "2023-06-14T05:42:11.644220Z" + }, + "sessions": [ + { + "id": "218380657934467329", + "creationDate": "2023-06-13T12:56:56.683629Z", + "changeDate": "2023-06-13T12:56:56.724450Z", + "sequence": "574", + "factors": { + "user": { + "verifiedAt": "2023-06-13T12:56:55.440850Z", + "id": "218380659823356328", + "loginName": "minnie-mouse@fabi.zitadel.app", + "displayName": "Minnie Mouse" + }, + "password": { + "verifiedAt": "2023-06-13T12:56:56.675359Z" + } + } + }, + { + "id": "218480890961985793", + "creationDate": "2023-06-14T05:32:38.977954Z", + "changeDate": "2023-06-14T05:42:11.631901Z", + "sequence": "582", + "factors": { + "user": { + "verifiedAt": "2023-06-14T05:32:38.972712Z", + "id": "218380659823356328", + "loginName": "minnie-mouse@fabi.zitadel.app", + "displayName": "Minnie Mouse" + }, + "password": { + "verifiedAt": "2023-06-14T05:42:11.619484Z" + } + } + } + ] +} +``` \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/external-login.mdx b/docs/docs/guides/integrate/login-ui/external-login.mdx new file mode 100644 index 000000000..81da1dcae --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/external-login.mdx @@ -0,0 +1,209 @@ +--- +title: Handle External Login +sidebar_label: External Identity Provider +--- + +## Flow + +The prerequisite for adding an external login (social and enterprise) to your user account is a registered identity provider on your ZITADEL instance or the organization of the user. +If you haven’t added a provider yet, have a look at the following guide first: [Identity Providers](https://zitadel.com/docs/guides/integrate/identity-providers) + +![Identity Provider Flow](/img/guides/login-ui/external-login-flow.png) + +## Start the Provider Flow + +ZITADEL will handle as much as possible from the authentication flow with the external provider. +This requires you to initiate the flow with your desired provider. + +Send the following two URLs in the request body: +1. SuccessURL: Page that should be shown when the login was successful +2. ErrorURL: Page that should be shown when an error happens during the authentication + +In the response, you will get an authentication URL of the provider you like. +[Start Identity Provider Flow Documentation](https://zitadel.com/docs/apis/resources/user_service/user-service-start-identity-provider-flow) + +### Request + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/idps/$IDP_ID/start \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "successUrl": "https://custom.com/login/idp/success", + "failureUrl": "https://custom.com/login/idp/fail" +}' +``` + +### Response + +```bash +{ + "details": { + "sequence": "592", + "changeDate": "2023-06-14T12:51:29.654819Z", + "resourceOwner": "163840776835432705" + }, + "authUrl": "https://accounts.google.com/o/oauth2/v2/auth?client_id=Test&prompt=select_account&redirect_uri=https%3A%2F%2F$ZITADEL_DOMAIN%2Fidps%2Fcallback&response_type=code&scope=openid+profile+email&state=218525066445455617" +} +``` + +## Call Provider + +The next step is to call the auth URL you got in the response from the previous step. +This will open up the login page of the given provider. In this guide, it is Google Login. + +```bash +https://accounts.google.com/o/oauth2/v2/auth?client_id=Test&prompt=select_account&redirect_uri=https%3A%2F%2F$ZITADEL_DOMAIN%2Fidps%2Fcallback&response_type=code&scope=openid+profile+email&state=218525066445455617 +``` + +After the user has successfully authenticated, a redirect to the ZITADEL backend /idps/callback will automatically be performed. + +## Get Provider Information + +ZITADEL will take the information of the provider. After this, a redirect will be made to either the success page in case of a successful login or to the error page in case of a failure will be performed. In the parameters, you will provide the intentID, a token, and optionally, if a user could be found, a user ID. + +To get the information of the provider, make a request to ZITADEL. +[Get Identity Provider Information Documentation](https://zitadel.com/docs/apis/resources/user_service/user-service-retrieve-identity-provider-information) + +### Request +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/intents/$INTENT_ID/information \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "token": "k50WQmDaPIazQDJsyKaEPaQPwgsytxqgQ3K1ifQeQtAmeQ" +}' +``` + +### Response + +```bash +{ + "details": { + "sequence": "599", + "changeDate": "2023-06-15T06:44:26.039444Z", + "resourceOwner": "163840776835432705" + }, + "idpInformation": { + "oauth": { + "accessToken": "ya29.a0AWY7CknrOORopcJK2XX2fQXV9NQpp8JdkKYx-mQZNrR-wktWWhc3QsepT6kloSCgFPS9N0beEBlEYoY5oYUhfc7VlLHTQz5iECE386pyx5YmTueyeQ9GXk1dAw89gi8KRyjNlJApFsfLJaoiLIvKJLf23eAyXgaCgYKAUMSARESFQG1tDrpnTJ2su8BBO24zfmzgneARw0165", + "idToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ijg1YmE5MzEzZmQ3YTdkNGFmYTg0ODg0YWJjYzg0MDMwMDQzNjMxODAiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIxODI5MDIwMjY1MDgtdW1taXQ3dHZjbHBnM2NxZmM4b2ljdGE1czI1aGtudWwuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIxODI5MDIwMjY1MDgtdW1taXQ3dHZjbHBnM2NxZmM4b2ljdGE1czI1aGtudWwuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTEzOTI4MDU5NzU3MTU4NTY2MzciLCJoZCI6InJvb3RkLmNoIiwiZW1haWwiOiJmYWJpZW5uZUByb290ZC5jaCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhdF9oYXNoIjoidGN5X25JTkZHNnFhRTBZTWFsQzZGdyIsIm5hbWUiOiJGYWJpZW5uZSBCw7xobGVyIiwicGljdHVyZSI6Imh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9hL0FBY0hUdGY5NzNRNk5IOEt6S1RNRVpFTFBVOWx4NDVXcFE5RlJCdXhGZFBiPXM5Ni1jIiwiZ2l2ZW5fbmFtZSI6IkZhYmllbm5lIiwiZmFtaWx5X25hbWUiOiJCw7xobGVyIiwibG9jYWxlIjoiZGUiLCJpYXQiOjE2ODY4MTE0NjUsImV4cCI6MTY4NjgxNTA2NX0.PwlAHRM44e8eYyHzdfotOrcq5GZc4D15mWvN3rGdoDmu2RRgb4T0nDgkY6AVq2vNJxPfbiB1jFtNP6dgX-OgLIxNXg_tJJhwFh-eFPA37cIiv1CEcgEC-q1zXFIa3HrwHLreeU6i7C9JkDrKpkS-AKat1krf27QXxrxHLrWehi5F2l1OZuAKFWYaYmJOd0sVTDBA2o5SDcAiQs_D4-Q-kSl5f0gh607YVHLv7zjyfHtAOs7xPEkNEUVcqGBke2Zy9kAYIgiMriNxLA2EDxFtSyWnf-bCXKnuVX2hwEY0T0lUPrOAVkz7MEOKiacE2xAOczoQvl-wECU0UofLi8XZqg" + }, + "idpId": "218528353504723201", + "rawInformation": { + "User": { + "email": "fabienne@rootd.ch", + "email_verified": true, + "family_name": "Bühler", + "given_name": "Fabienne", + "hd": "rootd.ch", + "locale": "de", + "name": "Fabienne Bühler", + "picture": "https://lh3.googleusercontent.com/a/AAcKTtf973Q6NH8KzKTMEZELPU9lx45WpQ9FRBuxFdPb=s96-c", + "sub": "111392805975715856637" + } + } + } +} +``` + +## Handle Provider Information +After successfully authenticating using your identity provider, you have three possible options. +1. Login +2. Register user +3. Add social login to existing user + +### Login + +If you did get a user ID in the parameters when calling your success page, you know that a user is already linked with the used identity provider and you are ready to perform the login. +Create a new session and include the intent ID and the token in the checks. +This check requires that the previous step ended on the successful page and didn't’t result in an error. + +#### 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": { + "userId": "218662596918640897" + }, + "intent": { + "intentId": "219647325729980673", + "token": "k86ihn-VLMMUGKy1q1b5i_foECspKYqei1l4mS8LT7Xzjw" + } + } +}' +``` + +### Register + +If you didn't get a user ID in the parameters of your success page, you know that there is no existing user in ZITADEL with that provider, and you can register a new user or link it to an existing account (read the next section). + +Fill the IdP links in the create user request to add a user with an external login provider. +The idpId is the ID of the provider in ZITADEL, the idpExternalId is the ID of the user in the external identity provider; usually, this is sent in the “sub”. +The display name is used to list the linkings on the users. + +[Create User API Documentation](https://zitadel.com/docs/apis/resources/user_service/user-service-add-human-user) + +#### Request +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/human \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "username": "minni-mouse@mouse.com", + "profile": { + "firstName": "Minnie", + "lastName": "Mouse", + "nickName": "Mini", + "displayName": "Minnie Mouse", + "preferredLanguage": "en", + "gender": "GENDER_FEMALE" + }, + "email": { + "email": "minni-mouse@mouse.com", + "isVerified": true + }, + "idpLinks": [ + { + "idpId": "218528353504723201", + "idpExternalId": "111392805975715856637", + "displayName": "Minnie Mouse" + } + ] +}' +``` + +### Add External Login to Existing User + +If you didn't get a user ID in the parameters to your success page, you know that there is no existing user in ZITADEL with that provider and you can register a new user (read previous section), or link it to an existing account. + +If you want to link/connect to an existing account you can perform the add identity provider link request. +[Add IDP Link to existing user documentation](https://zitadel.com/docs/apis/resources/user_service/user-service-add-idp-link) + +#### Request +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/users/218385419895570689/links \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "idpLink": { + "idpId": "218528353504723201", + "idpExternalId": "1113928059757158566371", + "displayName": "Minnie Mouse" + } +}' +``` \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/logout.mdx b/docs/docs/guides/integrate/login-ui/logout.mdx new file mode 100644 index 000000000..095f3b792 --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/logout.mdx @@ -0,0 +1,7 @@ +--- +title: Logout +--- + +import Logout from './_logout.mdx'; + + \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/oidc-standard.mdx b/docs/docs/guides/integrate/login-ui/oidc-standard.mdx new file mode 100644 index 000000000..0a7b5093a --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/oidc-standard.mdx @@ -0,0 +1,26 @@ +--- +title: OIDC Standard +--- + +:::info +Not yet implemented, but should give you a general impression of how it will work +Subscribe to the following issue: https://github.com/orgs/zitadel/projects/2/views/1?filterQuery=oidc&pane=issue&itemId=23181369 +::: + +To build your own login ui for your own application it is not necessary to have the OIDC standard included or any additional work that has to be done. +However, it might make sense, if you want to connect your login to different applications especially if they are not in your control and they rely on the standard. + +The following flow shows you the different components you need to enable OIDC for your login. +![OIDC Flow](/img/guides/login-ui/oidc-flow.png) + +1. Your application makes an authorization request to your login UI +2. The login UI takes the requests and sends them to the ZITADEL API. In the request to the ZITADEL API, a header to authenticate your client is needed. +3. The ZITADEL API parses the request and does what it needs to interpret certain parameters (e.g., organization scope, etc.) +4. Redirect to a predefined, relative URL of the login UI that includes the authrequest ID +5. Request to ZITADEL API to get all the information from the auth request +6. Create and update the session till the login flow is complete and the user is authenticated. Make sure to include the auth Request ID in the session +7. Read the callback URL from the ZITADEL API +8. Redirect to your application with the callback URL you got in the previous request +9. All OIDC-specific endpoints have to be accepted in the Login UI and should be proxied and sent to the ZITADEL API + + diff --git a/docs/docs/guides/integrate/login-ui/select-account.mdx b/docs/docs/guides/integrate/login-ui/select-account.mdx new file mode 100644 index 000000000..b7005aa23 --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/select-account.mdx @@ -0,0 +1,7 @@ +--- +title: Select Account +--- + +import SelectAccount from './_select-account.mdx'; + + \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/username-password.mdx b/docs/docs/guides/integrate/login-ui/username-password.mdx new file mode 100644 index 000000000..393aacaf0 --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/username-password.mdx @@ -0,0 +1,236 @@ +--- +title: Register and Login User with Password +sidebar_label: Username and Password +--- + +## Flow + +![Register and Login Flow](/img/guides/login-ui/username-password-flow.png) + +## Register + +First, we create a new user with a username and password. In the example below we add a user with profile data, a verified email address, and a password. +[Create User Documentation](https://zitadel.com/docs/apis/resources/user_service/user-service-add-human-user) + +### Request + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/human \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' \ + --header 'Content-Type: application/json' \ + --data '{ + "userId": "d654e6ba-70a3-48ef-a95d-37c8d8a7901a", + "username": "minnie-mouse", + "profile": { + "firstName": "Minnie", + "lastName": "Mouse", + "nickName": "Mini", + "displayName": "Minnie Mouse", + "preferredLanguage": "en", + "gender": "GENDER_FEMALE" + }, + "email": { + "email": "mini@mouse.com", + "isVerified": true + }, + "metadata": [ + { + "key": "my-key", + "value": "VGhpcyBpcyBteSB0ZXN0IHZhbHVl" + } + ], + "password": { + "password": "Secr3tP4ssw0rd!", + "changeRequired": false + } +}' +``` + +### Response + +```bash +{ + "userId": "d654e6ba-70a3-48ef-a95d-37c8d8a7901a", + "details": { + "sequence": "570", + "changeDate": "2023-06-13T12:44:36.967851Z", + "resourceOwner": "163840776835432705" + } +} +``` + +If you want the user to verify the email address you can either choose that ZITADEL sends a verification email to the user by adding a urlTemplate into the sendCode, or ask for a return code to send your own emails. + +Send Email by ZITADEL: + +```bash +"sendCode": { + "urlTemplate": "https://example.com/email/verify?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}" +}, +``` + +Return Code: +```bash +"email": { + "email": "mini@mouse.com", + "returnCode": {} +}, +``` + +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.) + +## Create Session with User Check + +After you have created a new user, you can redirect him to your login screen. +You can either create a new empty session as soon as the first login screen is shown or update it with each piece of information you get throughout the process. +Or you can create a new session with the first credentials a user enters. +In the following example, we assume that the login flow asks for the username in the first step, and in the second for the password. +In API requests, this means creating a new session with a username and updating it with the password. +If you already have the userId from a previous register, you can send it directly to skip the username and show the password screen directly. +The create and update session endpoints will always return a session ID and an opaque session token. +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) + +### 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@fabi.zitadel.app" + } + } +}' +``` + +### Response + +```bash +{ + "details": { + "sequence": "580", + "changeDate": "2023-06-14T05:32:39.007096Z", + "resourceOwner": "163840776835432705" + }, + "sessionId": "218480890961985793", + "sessionToken": "yMDi6uVPJAcphbbz0LaxC07ihWkNTe7m0Xqch8SzfM5Cz3HSIQIDZ65x1f5Qal0jxz0MEyo-_zYcUg" +} +``` + +### Session State + +If you read the newly created session, it will look like the following. +You can see the creation and change date. +In the factors, you will see all the checks that have been made. +In this case, the user has been checked. + +```bash +{ + "session": { + "id": "218480890961985793", + "creationDate": "2023-06-14T05:32:38.977954Z", + "changeDate": "2023-06-14T05:32:39.007096Z", + "sequence": "580", + "factors": { + "user": { + "verifiedAt": "2023-06-14T05:32:38.972712Z", + "id": "d654e6ba-70a3-48ef-a95d-37c8d8a7901a", + "loginName": "minnie-mouse@fabi.zitadel.app", + "displayName": "Minnie Mouse" + } + } + } +} +``` + +## Update Session with Password + +Your session already has a username check. +The next step is to check the password. +To update an existing session, add the session ID to the URL and the session token you got in the previous step to the request body. + +### Request + +```bash +curl --request PATCH \ + --url https://$ZITADEL_DOMAIN/v2alpha/sessions/$SESSION_ID \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"''\ + --header 'Content-Type: application/json' \ + --data '{ + "sessionToken": "yMDi6uVPJAcphbbz0LaxC07ihWkNTe7m0Xqch8SzfM5Cz3HSIQIDZ65x1f5Qal0jxz0MEyo-_zYcUg", + "checks": { + "password": { + "password": "Secr3tP4ssw0rd!" + } + } +}' +``` + +### Response + +The response of the create and update session token looks the same. +Make sure to always use the session token of the last response you got, as the values may be updated. + +```bash +{ + "details": { + "sequence": "582", + "changeDate": "2023-06-14T05:42:11.631901Z", + "resourceOwner": "163840776835432705" + }, + "sessionToken": "blGKerGQPKv8jN21p6E9GB1B-vl6_EyKlvTd5UALu8-aQmjucgZxHSXJx3XMFTwT9_Y3VnbOo3gC_Q" +} +``` + +### Session State +If you read your session after the password check, you will see that the check has been added to the factors with the verification date. + +```bash +{ + "session": { + "id": "218480890961985793", + "creationDate": "2023-06-14T05:32:38.977954Z", + "changeDate": "2023-06-14T05:42:11.631901Z", + "sequence": "582", + "factors": { + "user": { + "verifiedAt": "2023-06-14T05:32:38.972712Z", + "id": "d654e6ba-70a3-48ef-a95d-37c8d8a7901a", + "loginName": "minnie-mouse@fabi.zitadel.app", + "displayName": "Minnie Mouse" + }, + "password": { + "verifiedAt": "2023-06-14T05:42:11.619484Z" + } + } + } +} + +``` + +## List the Sessions (Account Chooser) + +import SelectAccount from './_select-account.mdx'; + + + +## Logout User + +import Logout from './_logout.mdx'; + + diff --git a/docs/sidebars.js b/docs/sidebars.js index cace2f404..609836685 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -167,6 +167,26 @@ module.exports = { "guides/integrate/pat", ], }, + { + type: "category", + label: "Build your own Login-UI", + link: { + type: "generated-index", + title: "Build your own Login-UI", + slug: "/guides/integrate/identity-providers", + description: + "In the following guides you will learn how to create your own login ui with our APIs. The different scenarios like username/password, external identity provider, etc will be shown.", + + }, + collapsed: true, + items: [ + "guides/integrate/login-ui/username-password", + "guides/integrate/login-ui/external-login", + "guides/integrate/login-ui/select-account", + "guides/integrate/login-ui/logout", + "guides/integrate/login-ui/oidc-standard" + ], + }, { type: "category", label: "Configure identity providers", diff --git a/docs/static/img/guides/login-ui/external-login-flow.png b/docs/static/img/guides/login-ui/external-login-flow.png new file mode 100644 index 000000000..c8678bb2c Binary files /dev/null and b/docs/static/img/guides/login-ui/external-login-flow.png differ diff --git a/docs/static/img/guides/login-ui/oidc-flow.png b/docs/static/img/guides/login-ui/oidc-flow.png new file mode 100644 index 000000000..552c357ba Binary files /dev/null and b/docs/static/img/guides/login-ui/oidc-flow.png differ diff --git a/docs/static/img/guides/login-ui/username-password-flow.png b/docs/static/img/guides/login-ui/username-password-flow.png new file mode 100644 index 000000000..7be7810b0 Binary files /dev/null and b/docs/static/img/guides/login-ui/username-password-flow.png differ