mirror of
https://github.com/zitadel/zitadel.git
synced 2025-04-15 18:51:31 +00:00
Merge branch 'main' into rename-topt
This commit is contained in:
commit
1461977d93
4826
console/package-lock.json
generated
4826
console/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,18 +12,18 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^16.0.1",
|
"@angular/animations": "^16.1.2",
|
||||||
"@angular/cdk": "^16.0.1",
|
"@angular/cdk": "^16.1.2",
|
||||||
"@angular/common": "^16.0.1",
|
"@angular/common": "^16.1.2",
|
||||||
"@angular/compiler": "^16.0.1",
|
"@angular/compiler": "^16.1.2",
|
||||||
"@angular/core": "^16.0.1",
|
"@angular/core": "^16.1.2",
|
||||||
"@angular/forms": "^16.0.1",
|
"@angular/forms": "^16.1.2",
|
||||||
"@angular/material": "^16.0.1",
|
"@angular/material": "^16.1.2",
|
||||||
"@angular/material-moment-adapter": "^16.0.1",
|
"@angular/material-moment-adapter": "^16.1.2",
|
||||||
"@angular/platform-browser": "^16.0.1",
|
"@angular/platform-browser": "^16.1.2",
|
||||||
"@angular/platform-browser-dynamic": "^16.0.1",
|
"@angular/platform-browser-dynamic": "^16.1.2",
|
||||||
"@angular/router": "^16.0.1",
|
"@angular/router": "^16.1.2",
|
||||||
"@angular/service-worker": "^16.0.1",
|
"@angular/service-worker": "^16.1.2",
|
||||||
"@ctrl/ngx-codemirror": "^6.1.0",
|
"@ctrl/ngx-codemirror": "^6.1.0",
|
||||||
"@grpc/grpc-js": "^1.8.14",
|
"@grpc/grpc-js": "^1.8.14",
|
||||||
"@ngx-translate/core": "^14.0.0",
|
"@ngx-translate/core": "^14.0.0",
|
||||||
@ -41,7 +41,8 @@
|
|||||||
"libphonenumber-js": "^1.10.30",
|
"libphonenumber-js": "^1.10.30",
|
||||||
"material-design-icons-iconfont": "^6.1.1",
|
"material-design-icons-iconfont": "^6.1.1",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"ngx-color": "^8.0.3",
|
"opentype.js": "^1.3.4",
|
||||||
|
"ngx-color": "^9.0.0",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tinycolor2": "^1.6.0",
|
"tinycolor2": "^1.6.0",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
@ -49,25 +50,26 @@
|
|||||||
"zone.js": "~0.13.0"
|
"zone.js": "~0.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^16.0.1",
|
"@angular-devkit/build-angular": "^16.1.1",
|
||||||
"@angular-eslint/builder": "16.0.1",
|
"@angular-eslint/builder": "16.0.1",
|
||||||
"@angular-eslint/eslint-plugin": "16.0.1",
|
"@angular-eslint/eslint-plugin": "16.0.1",
|
||||||
"@angular-eslint/eslint-plugin-template": "16.0.1",
|
"@angular-eslint/eslint-plugin-template": "16.0.1",
|
||||||
"@angular-eslint/schematics": "16.0.1",
|
"@angular-eslint/schematics": "16.0.1",
|
||||||
"@angular-eslint/template-parser": "16.0.1",
|
"@angular-eslint/template-parser": "16.0.1",
|
||||||
"@angular/cli": "^16.0.1",
|
"@angular/cli": "^16.1.1",
|
||||||
"@angular/compiler-cli": "^16.0.1",
|
"@angular/compiler-cli": "^16.1.2",
|
||||||
"@angular/language-service": "^16.0.1",
|
"@angular/language-service": "^16.1.2",
|
||||||
"@bufbuild/buf": "^1.18.0-1",
|
"@bufbuild/buf": "^1.18.0-1",
|
||||||
"@types/file-saver": "^2.0.2",
|
"@types/file-saver": "^2.0.2",
|
||||||
"@types/google-protobuf": "^3.15.3",
|
"@types/google-protobuf": "^3.15.3",
|
||||||
"@types/jasmine": "~4.3.0",
|
"@types/jasmine": "~4.3.3",
|
||||||
"@types/jasminewd2": "~2.0.10",
|
"@types/jasminewd2": "~2.0.10",
|
||||||
"@types/jsonwebtoken": "^9.0.1",
|
"@types/jsonwebtoken": "^9.0.1",
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^18.15.11",
|
||||||
|
"@types/opentype.js": "^1.3.4",
|
||||||
"@types/qrcode": "^1.5.0",
|
"@types/qrcode": "^1.5.0",
|
||||||
"@types/uuid": "^9.0.1",
|
"@types/uuid": "^9.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.2",
|
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
||||||
"@typescript-eslint/parser": "^5.59.5",
|
"@typescript-eslint/parser": "^5.59.5",
|
||||||
"codelyzer": "^6.0.2",
|
"codelyzer": "^6.0.2",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.39.0",
|
||||||
|
@ -492,7 +492,9 @@
|
|||||||
</cnsl-info-section>
|
</cnsl-info-section>
|
||||||
<div class="font-preview" *ngIf="previewData.fontUrl; else addFontButton">
|
<div class="font-preview" *ngIf="previewData.fontUrl; else addFontButton">
|
||||||
<mat-icon class="icon">text_fields</mat-icon>
|
<mat-icon class="icon">text_fields</mat-icon>
|
||||||
|
<span class="font-name" [ngStyle]="fontName ? { 'font-family': 'brandingFont' } : { '': '' }">{{
|
||||||
|
fontName
|
||||||
|
}}</span>
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@ -634,6 +636,7 @@
|
|||||||
class="preview"
|
class="preview"
|
||||||
[ngClass]="{ darkmode: theme === Theme.DARK, lightmode: theme === Theme.LIGHT }"
|
[ngClass]="{ darkmode: theme === Theme.DARK, lightmode: theme === Theme.LIGHT }"
|
||||||
[policy]="view === View.PREVIEW ? previewData : data"
|
[policy]="view === View.PREVIEW ? previewData : data"
|
||||||
|
[ngStyle]="fontName ? { 'font-family': 'brandingFont' } : { '': '' }"
|
||||||
>
|
>
|
||||||
</cnsl-preview>
|
</cnsl-preview>
|
||||||
</div>
|
</div>
|
||||||
|
@ -243,8 +243,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.font-preview {
|
.font-preview {
|
||||||
height: 70px;
|
|
||||||
width: 70px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -252,22 +250,17 @@
|
|||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
border: 1px solid map-get($foreground, divider);
|
border: 1px solid map-get($foreground, divider);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
padding: 1rem 0.5rem 1rem 0.75rem;
|
||||||
|
|
||||||
.icon {
|
.font-name {
|
||||||
position: absolute;
|
margin-left: 0.5rem;
|
||||||
top: 50%;
|
font-size: 16px;
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%) translateY(-50%);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dl-btn {
|
.dl-btn {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
transform: translateX(50%) translateY(-50%);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -31,6 +31,7 @@ import {
|
|||||||
} from 'src/app/services/theme.service';
|
} from 'src/app/services/theme.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
|
import * as opentype from 'opentype.js';
|
||||||
import { InfoSectionType } from '../../info-section/info-section.component';
|
import { InfoSectionType } from '../../info-section/info-section.component';
|
||||||
import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
|
import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
|
||||||
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||||
@ -88,6 +89,8 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
|
|||||||
public ColorType: any = ColorType;
|
public ColorType: any = ColorType;
|
||||||
public AssetType: any = AssetType;
|
public AssetType: any = AssetType;
|
||||||
|
|
||||||
|
public fontName = '';
|
||||||
|
|
||||||
public refreshPreview: EventEmitter<void> = new EventEmitter();
|
public refreshPreview: EventEmitter<void> = new EventEmitter();
|
||||||
public org!: Org.AsObject;
|
public org!: Org.AsObject;
|
||||||
public InfoSectionType: any = InfoSectionType;
|
public InfoSectionType: any = InfoSectionType;
|
||||||
@ -180,6 +183,10 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
|
|||||||
if (file) {
|
if (file) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
|
|
||||||
|
this.getFontName(file);
|
||||||
|
this.previewNewFont(file);
|
||||||
|
|
||||||
switch (this.serviceType) {
|
switch (this.serviceType) {
|
||||||
case PolicyComponentServiceType.MGMT:
|
case PolicyComponentServiceType.MGMT:
|
||||||
return this.handleFontUploadPromise(this.assetService.upload(AssetEndpoint.MGMTFONT, formData, this.org.id));
|
return this.handleFontUploadPromise(this.assetService.upload(AssetEndpoint.MGMTFONT, formData, this.org.id));
|
||||||
@ -199,6 +206,7 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
|
|||||||
this.getPreviewData().then((data) => {
|
this.getPreviewData().then((data) => {
|
||||||
if (data.policy) {
|
if (data.policy) {
|
||||||
this.previewData = data.policy;
|
this.previewData = data.policy;
|
||||||
|
this.fontName = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@ -374,6 +382,11 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.policy) {
|
if (data.policy) {
|
||||||
this.previewData = data.policy;
|
this.previewData = data.policy;
|
||||||
|
if (this.previewData?.fontUrl) {
|
||||||
|
this.fetchFontMetadataAndPreview(this.previewData.fontUrl);
|
||||||
|
} else {
|
||||||
|
this.fontName = 'Could not parse font name';
|
||||||
|
}
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -385,6 +398,11 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.policy) {
|
if (data.policy) {
|
||||||
this.data = data.policy;
|
this.data = data.policy;
|
||||||
|
if (this.data?.fontUrl) {
|
||||||
|
this.fetchFontMetadataAndPreview(this.data?.fontUrl);
|
||||||
|
} else {
|
||||||
|
this.fontName = 'Could not parse font name';
|
||||||
|
}
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -678,6 +696,45 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fetchFontMetadataAndPreview(url: string): void {
|
||||||
|
fetch(url)
|
||||||
|
.then((res) => res.blob())
|
||||||
|
.then((blob) => {
|
||||||
|
this.getFontName(blob);
|
||||||
|
this.previewNewFont(blob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getFontName(blob: Blob): void {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
if (e.target && e.target.result) {
|
||||||
|
try {
|
||||||
|
const font = opentype.parse(e.target.result);
|
||||||
|
this.fontName = font.names.fullName['en'];
|
||||||
|
} catch (e) {
|
||||||
|
this.fontName = 'Could not parse font name';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsArrayBuffer(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
private previewNewFont(blob: Blob): void {
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = (e) => {
|
||||||
|
if (e.target) {
|
||||||
|
let customFont = new FontFace('brandingFont', `url(${e.target.result})`);
|
||||||
|
// typescript complains that add is not found but
|
||||||
|
// indeed it is https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/add
|
||||||
|
// @ts-ignore
|
||||||
|
document.fonts.add(customFont);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * defaults to false because urls are distinct anyway
|
// * defaults to false because urls are distinct anyway
|
||||||
// */
|
// */
|
||||||
|
20
docs/docs/guides/integrate/login-ui/_logout.mdx
Normal file
20
docs/docs/guides/integrate/login-ui/_logout.mdx
Normal file
@ -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”.
|
80
docs/docs/guides/integrate/login-ui/_select-account.mdx
Normal file
80
docs/docs/guides/integrate/login-ui/_select-account.mdx
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
209
docs/docs/guides/integrate/login-ui/external-login.mdx
Normal file
209
docs/docs/guides/integrate/login-ui/external-login.mdx
Normal file
@ -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)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 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"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
7
docs/docs/guides/integrate/login-ui/logout.mdx
Normal file
7
docs/docs/guides/integrate/login-ui/logout.mdx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
title: Logout
|
||||||
|
---
|
||||||
|
|
||||||
|
import Logout from './_logout.mdx';
|
||||||
|
|
||||||
|
<Logout/>
|
26
docs/docs/guides/integrate/login-ui/oidc-standard.mdx
Normal file
26
docs/docs/guides/integrate/login-ui/oidc-standard.mdx
Normal file
@ -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.
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
7
docs/docs/guides/integrate/login-ui/select-account.mdx
Normal file
7
docs/docs/guides/integrate/login-ui/select-account.mdx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
title: Select Account
|
||||||
|
---
|
||||||
|
|
||||||
|
import SelectAccount from './_select-account.mdx';
|
||||||
|
|
||||||
|
<SelectAccount/>
|
236
docs/docs/guides/integrate/login-ui/username-password.mdx
Normal file
236
docs/docs/guides/integrate/login-ui/username-password.mdx
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
---
|
||||||
|
title: Register and Login User with Password
|
||||||
|
sidebar_label: Username and Password
|
||||||
|
---
|
||||||
|
|
||||||
|
## Flow
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 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';
|
||||||
|
|
||||||
|
<SelectAccount/>
|
||||||
|
|
||||||
|
## Logout User
|
||||||
|
|
||||||
|
import Logout from './_logout.mdx';
|
||||||
|
|
||||||
|
<Logout/>
|
@ -167,6 +167,26 @@ module.exports = {
|
|||||||
"guides/integrate/pat",
|
"guides/integrate/pat",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
label: "Build your own Login-UI",
|
||||||
|
link: {
|
||||||
|
type: "generated-index",
|
||||||
|
title: "Build your own Login-UI",
|
||||||
|
slug: "/guides/integrate/login-ui",
|
||||||
|
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",
|
type: "category",
|
||||||
label: "Configure identity providers",
|
label: "Configure identity providers",
|
||||||
|
BIN
docs/static/img/guides/login-ui/external-login-flow.png
vendored
Normal file
BIN
docs/static/img/guides/login-ui/external-login-flow.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 280 KiB |
BIN
docs/static/img/guides/login-ui/oidc-flow.png
vendored
Normal file
BIN
docs/static/img/guides/login-ui/oidc-flow.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 254 KiB |
BIN
docs/static/img/guides/login-ui/username-password-flow.png
vendored
Normal file
BIN
docs/static/img/guides/login-ui/username-password-flow.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 270 KiB |
Loading…
x
Reference in New Issue
Block a user