Merge branch 'rc' into next-rc

This commit is contained in:
adlerhurst 2023-06-01 13:12:00 +02:00
commit e3987d6555
178 changed files with 10804 additions and 3303 deletions

View File

@ -7,6 +7,7 @@
/k8s/
/node_modules/
/console/src/app/proto/generated/
/console/.angular
/console/tmp/
.releaserc.js
changelog.config.js
@ -18,3 +19,4 @@ pkg/grpc/*/*.pb.*
pkg/grpc/*/*.swagger.json
.goreleaser.yaml
.artifacts/
.vscode

View File

@ -7,6 +7,7 @@
- [ ] All open todos and follow ups are defined in a new ticket and justified
- [ ] Deviations from the acceptance criteria and design are agreed with the PO and documented.
- [ ] No debug or dead code
- [ ] My code has no repetitions
- [ ] Critical parts are tested automatically
- [ ] Where possible E2E tests are implemented
- [ ] Documentation/examples are up-to-date

View File

@ -43,7 +43,7 @@ jobs:
go run main.go init --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml
go run main.go setup --masterkeyFromEnv --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml
- name: Run integration tests
run: go test -tags=integration -race -parallel 1 -v -coverprofile=profile.cov -coverpkg=./... ./internal/integration ./internal/api/grpc/...
run: go test -tags=integration -race -parallel 1 -v -coverprofile=profile.cov -coverpkg=./internal/...,./cmd/... ./internal/integration ./internal/api/grpc/...
- name: Publish go coverage
uses: codecov/codecov-action@v3.1.0
with:

View File

@ -80,7 +80,7 @@ jobs:
name: go-codecov
- name: Bump Chart Version
uses: peter-evans/repository-dispatch@v2
if: steps.semantic.outputs.new_release_published == 'true' && github.ref == 'refs/heads/main'
if: steps.semantic.outputs.new_release_published == 'true' && github.ref == 'refs/heads/next'
with:
token: ${{ steps.generate-token.outputs.token }}
repository: zitadel/zitadel-charts

View File

@ -18,6 +18,7 @@ before:
- docker build -f build/grpc/Dockerfile -t zitadel-base:local .
- docker build -f build/zitadel/Dockerfile . -t zitadel-go-test --target go-codecov -o .artifacts/codecov
- docker build -f build/zitadel/Dockerfile . -t zitadel-go-base --target go-copy -o .artifacts/grpc/go-client
- sh -c "find pkg/grpc -name '*.pb*.go' -delete"
- sh -c "cp -r .artifacts/grpc/go-client/* ."
- docker build -f build/console/Dockerfile . -t zitadel-npm-console --target angular-export -o .artifacts/console
- sh -c "cp -r .artifacts/console/* internal/api/ui/console/static/"

View File

@ -2,6 +2,7 @@ module.exports = {
branches: [
{ name: 'main' },
{ name: 'next' },
{ name: 'rc', prerelease: true },
],
plugins: [
"@semantic-release/commit-analyzer"

View File

@ -36,7 +36,7 @@ We strongly recommend to [talk to us](https://zitadel.com/contact) before you st
We accept contributions through pull requests. You need a github account for that. If you are unfamiliar with git have a look at Github's documentation on [creating forks](https://help.github.com/articles/fork-a-repo) and [creating pull requests](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork). Please draft the pull request as soon as possible. Go through the following checklist before you submit the final pull request:
### Submit a Pull Request (PR)
### Submit a pull request (PR)
1. [Fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo) the [zitadel/zitadel](https://github.com/zitadel/zitadel) repository on GitHub
2. On your fork, commit your changes to a new branch
@ -59,14 +59,14 @@ We accept contributions through pull requests. You need a github account for tha
8. On GitHub, [send a pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review) to `zitadel:main`. Request review from one of the maintainers.
### Reviewing a Pull Request
### Review a pull request
The reviewers will provide you feedback and approve your changes as soon as they are satisfied. If we ask you for changes in the code, you can follow the [GitHub Guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request) to incorporate feedback in your pull request.
<!-- TODO: how to do this via git -->
<!-- TODO: change commit message via git -->
### Commit Messages
### Commit messages
Make sure you use [semantic release messages format](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#type).
@ -84,7 +84,7 @@ Must be one of the following:
This is optional to indicate which component is affected. In doubt, leave blank (`<type>: <short summary>`)
#### Short Summary
#### Short summary
Provide a brief description of the change.
@ -107,7 +107,7 @@ We add the label "good first issue" for problems we think are a good starting po
- [Issues for first time contributors](https://github.com/zitadel/zitadel/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
- [All issues](https://github.com/zitadel/zitadel/issues)
### Backend / Login
### Backend/login
By executing the commands from this section, you run everything you need to develop the ZITADEL backend locally.
Using [Docker Compose](https://docs.docker.com/compose/), you run a [CockroachDB](https://www.cockroachlabs.com/docs/stable/start-a-local-cluster-in-docker-mac.html) on your local machine.
@ -231,7 +231,6 @@ The commands in this section are tested against the following software versions:
- [Node version v16.17.0](https://nodejs.org/en/download/)
- [npm version 8.18.0](https://docs.npmjs.com/try-the-latest-stable-version-of-npm)
- [Cypress runtime dependencies](https://docs.cypress.io/guides/continuous-integration/introduction#Dependencies)
- [curl version 7.58.0](https://curl.se/download.html)
<details>
<summary>Note for WSL2 on Windows 10</summary>
@ -269,18 +268,17 @@ To allow console access via http://localhost:4200, you have to configure the ZIT
You can run the local console development server now.
```bash
# Console loads its target environment from the file console/src/assets/environment.json.
# Load it from the backend.
curl http://localhost:8080/ui/console/assets/environment.json > ./src/assets/environment.json
# Install npm dependencies
npm install
# Generate source files from Protos
npm run generate
# Install npm dependencies
npm install
# Start the server
npm start
# If you don't want to develop against http://localhost:8080, you can use another environment
ENVIRONMENT_JSON_URL=https://my-cloud-instance-abcdef.zitadel.cloud/ui/console/assets/environment.json npm start
```
Navigate to http://localhost:4200/.
@ -326,25 +324,36 @@ When you are happy with your changes, you can format your code and cleanup your
docker compose down
```
## Contribute Docs
## Contribute docs
Project documentation is made with docusaurus and is located under [./docs](./docs).
### Local Testing
### Local testing
Please refer to the [README](./docs/README.md) for more information and local testing.
### Style Guide
### Style guide
- **Code with variables**: Make sure that code snippets can be used by setting environment variables, instead of manually replacing a placeholder.
- **Embedded files**: When embedding mdx files, make sure the template ist prefixed by "_" (lowdash). The content will be rendered inside the parent page, but is not accessible individually (eg, by search).
- **Don't repeat yourself**: When using the same content in multiple places, save and manage the content as separate file and make use of embedded files to import it into other docs pages.
- **Embedded code**: You can embed code snippets from a repository. See the [plugin](https://github.com/saucelabs/docusaurus-theme-github-codeblock#usage) for usage.
### Docs Pull Request
Following the [Google style guide](https://developers.google.com/style) is highly recommended. Its clear and concise guidelines ensure consistency and effective communication within the wider developer community.
The style guide covers a lot of material, so their [highlights](https://developers.google.com/style/highlights) page provides an overview of its most important points. Some of the points stated in the highlights that we care about most are given below:
- Be conversational and friendly without being frivolous.
- Use sentence case for document titles and section headings.
- Use active voice: make clear who's performing the action.
- Use descriptive link text.
### Docs pull request
When making a pull request use `docs(<scope>): <short summary>` as title for the semantic release.
Scope can be left empty (omit the brackets) or refer to the top navigation sections.
## Contribute Internationalization
## Contribute internationalization
ZITADEL loads translations from four files:
@ -364,7 +373,7 @@ You can find an installation guide for all the different environments here:
- Please read [Security Policy](./SECURITY.md).
## Product Management
## Product management
The ZITADEL Team works with an agile product management methodology.
You can find all the issues prioritized and ordered in the [product board](https://github.com/orgs/zitadel/projects/2/views/1).
@ -388,10 +397,10 @@ The state should reflect the progress of the issue and what is going on right no
- **No status**: Issue just got added and has to be looked at.
- **🧐 Investigating**: We are currently investigating to find out what the problem is, which priority it should have and what has to be implemented. Or we need some more information from the author.
- **📨 Product Backlog**: If an issue is in the backlog, it is not currently being worked on. These are recorded so that they can be worked on in the future. Issues with this state do not have to be completely defined yet.
- **📝 Prioritized Product Backlog**: An issue with the state "Prioritized Backlog" is ready for the refinement from the perspective of the product owner (PO) to implement. This means the developer can find all the relevant information and acceptance criteria in the issue.
- **📨 Product backlog**: If an issue is in the backlog, it is not currently being worked on. These are recorded so that they can be worked on in the future. Issues with this state do not have to be completely defined yet.
- **📝 Prioritized product backlog**: An issue with the state "Prioritized Backlog" is ready for the refinement from the perspective of the product owner (PO) to implement. This means the developer can find all the relevant information and acceptance criteria in the issue.
- **🔖 Ready**: The issue is ready to take into a sprint. Difference to "prioritized..." is that the complexity is defined by the team.
- **📋 Sprint Backlog**: The issue is scheduled for the current sprint.
- **📋 Sprint backlog**: The issue is scheduled for the current sprint.
- **🏗 In progress**: Someone is working on this issue right now. The issue will get an assignee as soon as it is in progress.
- **👀 In review**: The issue is in review. Please add someone to review your issue or let us know that it is ready to review with a comment on your pull request.
- **✅ Done**: The issue is implemented and merged to main.
@ -413,7 +422,7 @@ Everything that is higher than 8 should be split in smaller parts.
**1**, **2**, **3**, **5**, **8**, **13**
### About the Labels
### About the labels
There are a few general labels that don't belong to a specific category.

View File

@ -94,7 +94,7 @@ Authentication
- Single Sign On (SSO)
- Passwordless with FIDO2 support (Including Passkeys)
- Username / Password
- Multifactor authentication with OTP, U2F, SMS
- Multifactor authentication with OTP, U2F
- LDAP
- [OpenID Connect certified](https://openid.net/certification/#OPs) => [OIDC Endpoints](https://zitadel.com/docs/apis/openidoauth/endpoints)
- [SAML 2.0](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html) => [SAML Endpoints](https://zitadel.com/docs/apis/saml/endpoints)

View File

@ -735,6 +735,7 @@ InternalAuthZ:
- "user.grant.delete"
- "user.membership.read"
- "user.credential.write"
- "user.passkey.write"
- "policy.read"
- "policy.write"
- "policy.delete"
@ -811,6 +812,7 @@ InternalAuthZ:
- "user.grant.delete"
- "user.membership.read"
- "user.credential.write"
- "user.passkey.write"
- "policy.read"
- "policy.write"
- "policy.delete"
@ -847,6 +849,7 @@ InternalAuthZ:
- "user.grant.write"
- "user.grant.delete"
- "user.membership.read"
- "user.passkey.write"
- "project.read"
- "project.member.read"
- "project.role.read"
@ -882,6 +885,7 @@ InternalAuthZ:
- "user.grant.delete"
- "user.membership.read"
- "user.credential.write"
- "user.passkey.write"
- "policy.read"
- "policy.write"
- "policy.delete"

View File

@ -13,11 +13,11 @@ import (
)
var (
//go:embed 10_create_temp_table.sql
//go:embed 10/10_create_temp_table.sql
correctCreationDate10CreateTable string
//go:embed 10_fill_table.sql
//go:embed 10/10_fill_table.sql
correctCreationDate10FillTable string
//go:embed 10_update.sql
//go:embed 10/10_update.sql
correctCreationDate10Update string
)

32
cmd/setup/11.go Normal file
View File

@ -0,0 +1,32 @@
package setup
import (
"context"
_ "embed"
"github.com/zitadel/zitadel/internal/database"
)
var (
//go:embed 11.sql
addEventCreatedAt string
)
type AddEventCreatedAt struct {
step10 *CorrectCreationDate
dbClient *database.DB
}
func (mig *AddEventCreatedAt) Execute(ctx context.Context) error {
// execute step 10 again because events created after the first execution of step 10
// could still have the wrong ordering of sequences and creation date
if err := mig.step10.Execute(ctx); err != nil {
return err
}
_, err := mig.dbClient.ExecContext(ctx, addEventCreatedAt)
return err
}
func (mig *AddEventCreatedAt) String() string {
return "11_event_created_at"
}

15
cmd/setup/11.sql Normal file
View File

@ -0,0 +1,15 @@
BEGIN;
-- create table with empty created_at
ALTER TABLE eventstore.events ADD COLUMN created_at TIMESTAMPTZ DEFAULT NULL;
COMMIT;
BEGIN;
-- backfill created_at
UPDATE eventstore.events SET created_at = creation_date WHERE created_at IS NULL;
COMMIT;
BEGIN;
-- set column rules
ALTER TABLE eventstore.events ALTER COLUMN created_at SET DEFAULT clock_timestamp();
ALTER TABLE eventstore.events ALTER COLUMN created_at SET NOT NULL;
COMMIT;

View File

@ -66,6 +66,7 @@ type Steps struct {
s8AuthTokens *AuthTokenIndexes
s9EventstoreIndexes2 *EventstoreIndexesNew
CorrectCreationDate *CorrectCreationDate
s11AddEventCreatedAt *AddEventCreatedAt
}
type encryptionKeyConfig struct {

View File

@ -91,6 +91,7 @@ func Setup(config *Config, steps *Steps, masterKey string) {
steps.s8AuthTokens = &AuthTokenIndexes{dbClient: dbClient}
steps.s9EventstoreIndexes2 = New09(dbClient)
steps.CorrectCreationDate.dbClient = dbClient
steps.s11AddEventCreatedAt = &AddEventCreatedAt{dbClient: dbClient, step10: steps.CorrectCreationDate}
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil)
logging.OnError(err).Fatal("unable to start projections")
@ -128,6 +129,8 @@ func Setup(config *Config, steps *Steps, masterKey string) {
logging.OnError(err).Fatal("unable to migrate step 9")
err = migration.Migrate(ctx, eventstoreClient, steps.CorrectCreationDate)
logging.OnError(err).Fatal("unable to migrate step 10")
err = migration.Migrate(ctx, eventstoreClient, steps.s11AddEventCreatedAt)
logging.OnError(err).Fatal("unable to migrate step 11")
for _, repeatableStep := range repeatableSteps {
err = migration.Migrate(ctx, eventstoreClient, repeatableStep)

View File

@ -38,6 +38,7 @@ import (
"github.com/zitadel/zitadel/internal/api/grpc/user/v2"
http_util "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/api/idp"
"github.com/zitadel/zitadel/internal/api/oidc"
"github.com/zitadel/zitadel/internal/api/robots_txt"
"github.com/zitadel/zitadel/internal/api/saml"
@ -306,9 +307,8 @@ func startAPIs(
http_util.WithNonHttpOnly(),
http_util.WithMaxAge(int(math.Floor(config.Quotas.Access.ExhaustedCookieMaxAge.Seconds()))),
)
limitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, exhaustedCookieHandler, config.Quotas.Access, false)
nonLimitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, nil, config.Quotas.Access, true)
apis, err := api.New(ctx, config.Port, router, queries, verifier, config.InternalAuthZ, tlsConfig, config.HTTP2HostHeader, config.HTTP1HostHeader, accessSvc, exhaustedCookieHandler, config.Quotas.Access)
limitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, exhaustedCookieHandler, config.Quotas.Access)
apis, err := api.New(ctx, config.Port, router, queries, verifier, config.InternalAuthZ, tlsConfig, config.HTTP2HostHeader, config.HTTP1HostHeader, limitingAccessInterceptor)
if err != nil {
return fmt.Errorf("error creating api %w", err)
}
@ -332,7 +332,7 @@ func startAPIs(
if err := apis.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, keys.User, config.ExternalSecure, config.AuditLogRetention)); err != nil {
return err
}
if err := apis.RegisterService(ctx, user.CreateServer(commands, queries, keys.User)); err != nil {
if err := apis.RegisterService(ctx, user.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(config.ExternalSecure))); err != nil {
return err
}
if err := apis.RegisterService(ctx, session.CreateServer(commands, queries, permissionCheck)); err != nil {
@ -345,6 +345,8 @@ func startAPIs(
assetsCache := middleware.AssetsCacheInterceptor(config.AssetStorage.Cache.MaxAge, config.AssetStorage.Cache.SharedMaxAge)
apis.RegisterHandlerOnPrefix(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, middleware.CallDurationHandler, instanceInterceptor.Handler, assetsCache.Handler, limitingAccessInterceptor.Handle))
apis.RegisterHandlerOnPrefix(idp.HandlerPrefix, idp.NewHandler(commands, queries, keys.IDPConfig, config.ExternalSecure, instanceInterceptor.Handler))
userAgentInterceptor, err := middleware.NewUserAgentHandler(config.UserAgentCookie, keys.UserAgentCookieKey, id.SonyFlakeGenerator(), config.ExternalSecure, login.EndpointResources)
if err != nil {
return err
@ -376,7 +378,7 @@ func startAPIs(
}
apis.RegisterHandlerOnPrefix(saml.HandlerPrefix, samlProvider.HttpHandler())
c, err := console.Start(config.Console, config.ExternalSecure, oidcProvider.IssuerFromRequest, middleware.CallDurationHandler, instanceInterceptor.Handler, nonLimitingAccessInterceptor.Handle, config.CustomerPortal)
c, err := console.Start(config.Console, config.ExternalSecure, oidcProvider.IssuerFromRequest, middleware.CallDurationHandler, instanceInterceptor.Handler, limitingAccessInterceptor, config.CustomerPortal)
if err != nil {
return fmt.Errorf("unable to start console: %w", err)
}

View File

@ -35,7 +35,8 @@
"codemirror/mode/javascript/javascript",
"codemirror/mode/xml/xml",
"file-saver",
"qrcode"
"qrcode",
"codemirror"
]
},
"configurations": {

5303
console/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"start": "node prebuild.development.js && ng serve",
"build": "ng build --configuration production --base-href=/ui/console/",
"prelint": "npm run generate",
"lint": "ng lint && prettier --check src",
@ -12,26 +12,23 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^15.2.6",
"@angular/cdk": "^15.2.6",
"@angular/common": "^15.2.6",
"@angular/compiler": "^15.2.6",
"@angular/core": "^15.2.6",
"@angular/forms": "^15.2.6",
"@angular/material": "^15.2.6",
"@angular/material-moment-adapter": "^15.2.6",
"@angular/platform-browser": "^15.2.6",
"@angular/platform-browser-dynamic": "^15.2.6",
"@angular/router": "^15.2.6",
"@angular/service-worker": "^15.2.6",
"@angular/animations": "^16.0.1",
"@angular/cdk": "^16.0.1",
"@angular/common": "^16.0.1",
"@angular/compiler": "^16.0.1",
"@angular/core": "^16.0.1",
"@angular/forms": "^16.0.1",
"@angular/material": "^16.0.1",
"@angular/material-moment-adapter": "^16.0.1",
"@angular/platform-browser": "^16.0.1",
"@angular/platform-browser-dynamic": "^16.0.1",
"@angular/router": "^16.0.1",
"@angular/service-worker": "^16.0.1",
"@ctrl/ngx-codemirror": "^6.1.0",
"@grpc/grpc-js": "^1.8.12",
"@grpc/grpc-js": "^1.8.14",
"@ngx-translate/core": "^14.0.0",
"@types/file-saver": "^2.0.2",
"@types/google-protobuf": "^3.15.3",
"@types/uuid": "^8.3.0",
"angular-oauth2-oidc": "^15.0.1",
"angularx-qrcode": "^15.0.0",
"angularx-qrcode": "^16.0.0",
"buffer": "^6.0.3",
"codemirror": "^5.65.8",
"cors": "^2.8.5",
@ -40,8 +37,8 @@
"google-proto-files": "^3.0.3",
"google-protobuf": "^3.21.2",
"grpc-web": "^1.4.1",
"i18n-iso-countries": "^7.5.0",
"libphonenumber-js": "^1.10.24",
"i18n-iso-countries": "^7.6.0",
"libphonenumber-js": "^1.10.30",
"material-design-icons-iconfont": "^6.1.1",
"moment": "^2.29.4",
"ngx-color": "^8.0.3",
@ -52,31 +49,34 @@
"zone.js": "~0.13.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^15.2.5",
"@angular-eslint/builder": "15.2.1",
"@angular-eslint/eslint-plugin": "15.2.1",
"@angular-eslint/eslint-plugin-template": "15.2.1",
"@angular-eslint/schematics": "15.2.1",
"@angular-eslint/template-parser": "15.2.1",
"@angular/cli": "^15.2.5",
"@angular/compiler-cli": "^15.2.6",
"@angular/language-service": "^15.2.6",
"@bufbuild/buf": "^1.14.0",
"@angular-devkit/build-angular": "^16.0.1",
"@angular-eslint/builder": "16.0.1",
"@angular-eslint/eslint-plugin": "16.0.1",
"@angular-eslint/eslint-plugin-template": "16.0.1",
"@angular-eslint/schematics": "16.0.1",
"@angular-eslint/template-parser": "16.0.1",
"@angular/cli": "^16.0.1",
"@angular/compiler-cli": "^16.0.1",
"@angular/language-service": "^16.0.1",
"@bufbuild/buf": "^1.18.0-1",
"@types/file-saver": "^2.0.2",
"@types/google-protobuf": "^3.15.3",
"@types/jasmine": "~4.3.0",
"@types/jasminewd2": "~2.0.10",
"@types/jsonwebtoken": "^9.0.1",
"@types/node": "^18.15.11",
"@types/qrcode": "^1.5.0",
"@typescript-eslint/eslint-plugin": "5.48.2",
"@typescript-eslint/parser": "5.48.2",
"@types/uuid": "^9.0.1",
"@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/parser": "^5.59.5",
"codelyzer": "^6.0.2",
"eslint": "^8.33.0",
"eslint": "^8.39.0",
"jasmine-core": "~4.6.0",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.4.1",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~5.1.0",
"karma": "^6.4.2",
"karma-chrome-launcher": "^3.2.0",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "^2.0.0",
"prettier": "^2.8.7",
"prettier-plugin-organize-imports": "^3.2.2",

View File

@ -0,0 +1,28 @@
var fs = require('fs');
var path = require('path')
var http = require('http');
var https = require('https');
var urlModule = require('url');
var defaultEnvironmentJsonURL = 'http://localhost:8080/ui/console/assets/environment.json'
var devEnvFile = path.join(__dirname, "src", "assets", "environment.json")
var url = process.env["ENVIRONMENT_JSON_URL"] || defaultEnvironmentJsonURL;
var protocol = urlModule.parse(url).protocol;
var getter = protocol === 'https:' ? https.get : http.get;
getter(url, function (res) {
var body = '';
res.on('data', function (chunk) {
body += chunk;
});
res.on('end', function () {
fs.writeFileSync(devEnvFile, body);
console.log("Developing against the following environment")
console.log(JSON.stringify(JSON.parse(body), null, 4))
});
}).on('error', function (e) {
console.error("Got an error: ", e);
});

View File

@ -1,5 +1,5 @@
import { CommonModule, registerLocaleData } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import localeDe from '@angular/common/locales/de';
import localeEn from '@angular/common/locales/en';
import localeEs from '@angular/common/locales/es';
@ -27,7 +27,6 @@ import { RoleGuard } from 'src/app/guards/role.guard';
import { UserGuard } from 'src/app/guards/user.guard';
import { InfoOverlayModule } from 'src/app/modules/info-overlay/info-overlay.module';
import { AssetService } from 'src/app/services/asset.service';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HasRoleModule } from './directives/has-role/has-role.module';
@ -40,9 +39,13 @@ import { HasRolePipeModule } from './pipes/has-role-pipe/has-role-pipe.module';
import { AdminService } from './services/admin.service';
import { AuthenticationService } from './services/authentication.service';
import { BreadcrumbService } from './services/breadcrumb.service';
import { EnvironmentService } from './services/environment.service';
import { ExhaustedService } from './services/exhausted.service';
import { GrpcAuthService } from './services/grpc-auth.service';
import { GrpcService } from './services/grpc.service';
import { AuthInterceptor } from './services/interceptors/auth.interceptor';
import { ExhaustedGrpcInterceptor } from './services/interceptors/exhausted.grpc.interceptor';
import { ExhaustedHttpInterceptor } from './services/interceptors/exhausted.http.interceptor';
import { GRPC_INTERCEPTORS } from './services/interceptors/grpc-interceptor';
import { I18nInterceptor } from './services/interceptors/i18n.interceptor';
import { OrgInterceptor } from './services/interceptors/org.interceptor';
@ -84,9 +87,9 @@ export class WebpackTranslateLoader implements TranslateLoader {
}
}
const appInitializerFn = (grpcServ: GrpcService) => {
const appInitializerFn = (grpcSvc: GrpcService) => {
return () => {
return grpcServ.loadAppEnvironment();
return grpcSvc.loadAppEnvironment();
};
};
@ -139,6 +142,8 @@ const authConfig: AuthConfig = {
RoleGuard,
UserGuard,
ThemeService,
EnvironmentService,
ExhaustedService,
{
provide: APP_INITIALIZER,
useFactory: appInitializerFn,
@ -167,6 +172,16 @@ const authConfig: AuthConfig = {
provide: OAuthStorage,
useClass: StorageService,
},
{
provide: HTTP_INTERCEPTORS,
multi: true,
useClass: ExhaustedHttpInterceptor,
},
{
provide: GRPC_INTERCEPTORS,
multi: true,
useClass: ExhaustedGrpcInterceptor,
},
{
provide: GRPC_INTERCEPTORS,
multi: true,

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthConfig } from 'angular-oauth2-oidc';
import { Observable } from 'rxjs';
@ -8,7 +8,7 @@ import { AuthenticationService } from '../services/authentication.service';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
export class AuthGuard {
constructor(private auth: AuthenticationService) {}
public canActivate(

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { GrpcAuthService } from '../services/grpc-auth.service';
@ -7,7 +7,7 @@ import { GrpcAuthService } from '../services/grpc-auth.service';
@Injectable({
providedIn: 'root',
})
export class RoleGuard implements CanActivate {
export class RoleGuard {
constructor(private authService: GrpcAuthService) {}
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
@ -8,7 +8,7 @@ import { GrpcAuthService } from '../services/grpc-auth.service';
@Injectable({
providedIn: 'root',
})
export class UserGuard implements CanActivate {
export class UserGuard {
constructor(private authService: GrpcAuthService, private router: Router) {}
public canActivate(

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { PrivacyPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
@ -7,10 +7,12 @@ import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss'],
})
export class FooterComponent {
export class FooterComponent implements OnInit {
public policy?: PrivacyPolicy.AsObject;
constructor(public authService: GrpcAuthService) {
authService.getMyPrivacyPolicy().then((policyResp) => {
constructor(public authService: GrpcAuthService) {}
ngOnInit(): void {
this.authService.getMyPrivacyPolicy().then((policyResp) => {
if (policyResp.policy) {
this.policy = policyResp.policy;
}

View File

@ -228,7 +228,6 @@
(detach)="showAccount = false"
>
<cnsl-accounts-card
@accounts
class="a_card"
*ngIf="showAccount"
(closedCard)="showAccount = false"

View File

@ -5,13 +5,13 @@ import { MatIconModule } from '@angular/material/icon';
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
import { MatLegacyDialogModule as MatDialogModule } from '@angular/material/legacy-dialog';
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
import { MatLegacyTableModule as MatTableModule } from '@angular/material/legacy-table';
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
import { CardModule } from '../card/card.module';
import { MatLegacyTableModule } from '@angular/material/legacy-table';
import { InputModule } from '../input/input.module';
import { RefreshTableModule } from '../refresh-table/refresh-table.module';
import { MetadataDialogComponent } from './metadata-dialog/metadata-dialog.component';
@ -33,7 +33,7 @@ import { MetadataComponent } from './metadata/metadata.component';
LocalizedDatePipeModule,
TimestampToDatePipeModule,
RefreshTableModule,
MatTableModule,
MatLegacyTableModule,
],
exports: [MetadataComponent, MetadataDialogComponent],
})

View File

@ -83,7 +83,7 @@
</a>
<a
*ngIf="customerPortalLink"
*ngIf="customerPortalLink$ | async as customerPortalLink"
class="nav-item external-link"
[href]="customerPortalLink"
target="_blank"

View File

@ -1,16 +1,16 @@
import { animate, keyframes, style, transition, trigger } from '@angular/animations';
import { BreakpointObserver } from '@angular/cdk/layout';
import { ConnectedPosition, ConnectionPositionPair } from '@angular/cdk/overlay';
import { HttpClient } from '@angular/common/http';
import { Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { Router } from '@angular/router';
import { BehaviorSubject, combineLatest, map, Observable, Subject, take } from 'rxjs';
import { BehaviorSubject, combineLatest, map, Observable, Subject } from 'rxjs';
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
import { User } from 'src/app/proto/generated/zitadel/user_pb';
import { AdminService } from 'src/app/services/admin.service';
import { AuthenticationService } from 'src/app/services/authentication.service';
import { BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
import { EnvironmentService } from 'src/app/services/environment.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { KeyboardShortcutsService } from 'src/app/services/keyboard-shortcuts/keyboard-shortcuts.service';
import { ManagementService } from 'src/app/services/mgmt.service';
@ -90,7 +90,7 @@ export class NavComponent implements OnDestroy {
private destroy$: Subject<void> = new Subject();
public BreadcrumbType: any = BreadcrumbType;
public customerPortalLink: string = '';
public customerPortalLink$ = this.envService.env.pipe(map((env) => env.customer_portal));
public positions: ConnectedPosition[] = [
new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }, 0, 10),
@ -98,6 +98,7 @@ export class NavComponent implements OnDestroy {
];
constructor(
private envService: EnvironmentService,
public authService: GrpcAuthService,
public adminService: AdminService,
public authenticationService: AuthenticationService,
@ -105,23 +106,9 @@ export class NavComponent implements OnDestroy {
public mgmtService: ManagementService,
private router: Router,
private breakpointObserver: BreakpointObserver,
private http: HttpClient,
private shortcutService: KeyboardShortcutsService,
private storageService: StorageService,
) {
this.loadEnvironment();
}
public loadEnvironment(): void {
this.http
.get('./assets/environment.json')
.pipe(take(1))
.subscribe((data: any) => {
if (data && data.customer_portal) {
this.customerPortalLink = data.customer_portal;
}
});
}
) {}
public ngOnDestroy() {
this.destroy$.next();

View File

@ -6,7 +6,6 @@ import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/lega
import { MatLegacyDialogModule as MatDialogModule } from '@angular/material/legacy-dialog';
import { MatLegacyMenuModule as MatMenuModule } from '@angular/material/legacy-menu';
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
import { MatLegacyTabsModule as MatTabsModule } from '@angular/material/legacy-tabs';
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { CopyToClipboardModule } from 'src/app/directives/copy-to-clipboard/copy-to-clipboard.module';
@ -47,7 +46,6 @@ import { OrgRoutingModule } from './org-routing.module';
MatIconModule,
ReactiveFormsModule,
MetaLayoutModule,
MatTabsModule,
MatTooltipModule,
WarnDialogModule,
MemberCreateDialogModule,

View File

@ -2,7 +2,8 @@
title="{{ 'APP.PAGES.CREATE' | translate }}"
class="app-create-wrapper"
[createSteps]="
appType?.value?.createType === AppCreateType.OIDC
!devmode
? appType?.value?.createType === AppCreateType.OIDC
? appType?.value.oidcAppType !== OIDCAppType.OIDC_APP_TYPE_NATIVE
? 4
: 3
@ -11,6 +12,7 @@
: appType?.value?.createType === AppCreateType.SAML
? 3
: 0
: 0
"
[currentCreateStep]="currentCreateStep"
(closed)="close()"

View File

@ -397,8 +397,8 @@
</ng-container>
<ng-container *ngIf="currentSetting === 'urls'">
<cnsl-card title=" {{ 'APP.URLS' | translate }}">
<cnsl-info-section *ngIf="environmentMap['issuer']">
<cnsl-card title=" {{ 'APP.URLS' | translate }}" *ngIf="environmentMap$ | async as environmentMap">
<cnsl-info-section *ngIf="environmentMap.issuer">
<div
[innerHtml]="
'APP.OIDC.WELLKNOWN' | translate : { url: environmentMap['issuer'] + '/.well-known/openid-configuration' }
@ -426,7 +426,7 @@
</div>
<div class="app-info-row">
<div class="app-info-wrapper" *ngFor="let wellKnownV of wellKnownMap | keyvalue">
<div class="app-info-wrapper" *ngFor="let wellKnownV of wellKnownMap$ | async | keyvalue">
<p class="app-info-row-title cnsl-secondary-text">{{ wellKnownV.key }}</p>
<div class="app-copy-row">
<div *ngIf="wellKnownV.value" class="environment">

View File

@ -1,6 +1,5 @@
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { AbstractControl, FormControl, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatLegacyCheckboxChange as MatCheckboxChange } from '@angular/material/legacy-checkbox';
@ -10,7 +9,7 @@ import { TranslateService } from '@ngx-translate/core';
import { Buffer } from 'buffer';
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
import { Subject, Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { map, take } from 'rxjs/operators';
import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
import { ChangeType } from 'src/app/modules/changes/changes.component';
import { InfoSectionType } from 'src/app/modules/info-section/info-section.component';
@ -41,6 +40,7 @@ import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { EnvironmentService } from 'src/app/services/environment.service';
import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component';
import {
BASIC_AUTH_METHOD,
@ -79,8 +79,17 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public projectId: string = '';
public app?: App.AsObject;
public environmentMap: { [key: string]: string } = {};
public wellKnownMap: { [key: string]: string } = {};
public environmentMap$ = this.envSvc.env.pipe(
map((env) => {
return {
issuer: env.issuer,
adminServiceUrl: `${env.api}/admin/v1`,
mgmtServiceUrl: `${env.api}/management/v1`,
authServiceUrl: `${env.api}/auth/v1`,
};
}),
);
public wellKnownMap$ = this.envSvc.wellKnown;
public oidcResponseTypes: OIDCResponseType[] = [
OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
@ -138,6 +147,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public currentSetting: string | undefined = this.settingsList[0].id;
constructor(
private envSvc: EnvironmentService,
public translate: TranslateService,
private route: ActivatedRoute,
private toast: ToastService,
@ -148,7 +158,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
private authService: GrpcAuthService,
private router: Router,
private breadcrumbService: BreadcrumbService,
private http: HttpClient,
) {
this.oidcForm = this.fb.group({
devMode: [{ value: false, disabled: true }],
@ -176,25 +185,6 @@ export class AppDetailComponent implements OnInit, OnDestroy {
metadataUrl: [{ value: '', disabled: true }],
metadataXml: [{ value: '', disabled: true }],
});
this.http.get('./assets/environment.json').subscribe((env: any) => {
this.environmentMap = {
issuer: env.issuer,
adminServiceUrl: `${env.api}/admin/v1`,
mgmtServiceUrl: `${env.api}/management/v1`,
authServiceUrl: `${env.api}/auth/v1`,
};
this.http.get(`${env.issuer}/.well-known/openid-configuration`).subscribe((wellKnown: any) => {
this.wellKnownMap = {
authorization_endpoint: wellKnown.authorization_endpoint,
end_session_endpoint: wellKnown.end_session_endpoint,
introspection_endpoint: wellKnown.introspection_endpoint,
token_endpoint: wellKnown.token_endpoint,
userinfo_endpoint: wellKnown.userinfo_endpoint,
};
});
});
}
public formatClockSkewLabel(seconds: number): string {

View File

@ -9,7 +9,6 @@ import { MatLegacyProgressBarModule as MatProgressBarModule } from '@angular/mat
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
import { MatLegacyTableModule as MatTableModule } from '@angular/material/legacy-table';
import { MatLegacyTabsModule as MatTabsModule } from '@angular/material/legacy-tabs';
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
import { MatSortModule } from '@angular/material/sort';
import { TranslateModule } from '@ngx-translate/core';
@ -51,7 +50,6 @@ import { GrantedProjectsRoutingModule } from './granted-projects-routing.module'
MatIconModule,
MatSelectModule,
MatButtonModule,
MatTabsModule,
MatProgressSpinnerModule,
MetaLayoutModule,
MatProgressBarModule,

View File

@ -9,7 +9,6 @@ import { MatLegacyMenuModule as MatMenuModule } from '@angular/material/legacy-m
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
import { MatLegacyTableModule as MatTableModule } from '@angular/material/legacy-table';
import { MatLegacyTabsModule as MatTabsModule } from '@angular/material/legacy-tabs';
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
@ -53,7 +52,6 @@ import { OwnedProjectDetailComponent } from './owned-project-detail.component';
MatIconModule,
InfoRowModule,
ContributorsModule,
MatTabsModule,
WarnDialogModule,
MatTooltipModule,
ProjectRolesTableModule,

View File

@ -6,7 +6,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox';
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
import { MatLegacyTableModule as MatTableModule } from '@angular/material/legacy-table';
import { MatLegacyTableModule } from '@angular/material/legacy-table';
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
import { MatSortModule } from '@angular/material/sort';
import { TranslateModule } from '@ngx-translate/core';
@ -36,7 +36,7 @@ import { ProjectsComponent } from './projects.component';
TranslateModule,
FormsModule,
HasRoleModule,
MatTableModule,
MatLegacyTableModule,
PaginatorModule,
InputModule,
MatIconModule,

View File

@ -8,7 +8,6 @@ import { MatLegacyDialogModule as MatDialogModule } from '@angular/material/lega
import { MatLegacyMenuModule as MatMenuModule } from '@angular/material/legacy-menu';
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
import { MatLegacyTableModule as MatTableModule } from '@angular/material/legacy-table';
import { MatLegacyTabsModule as MatTabsModule } from '@angular/material/legacy-tabs';
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@ -87,7 +86,6 @@ import { UserMfaComponent } from './user-detail/user-mfa/user-mfa.component';
ChangesModule,
CommonModule,
SidenavModule,
MatTabsModule,
FormsModule,
ReactiveFormsModule,
MembershipsTableModule,

View File

@ -1,9 +1,10 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { lastValueFrom } from 'rxjs';
import { switchMap } from 'rxjs';
import { PolicyComponentServiceType } from '../modules/policies/policy-component-types.enum';
import { Theme } from '../modules/policies/private-labeling-policy/private-labeling-policy.component';
import { EnvironmentService } from './environment.service';
import { StorageService } from './storage.service';
const authorizationKey = 'Authorization';
@ -69,46 +70,29 @@ export const ENDPOINT = {
providedIn: 'root',
})
export class AssetService {
private serviceUrl!: Promise<string>;
private accessToken: string = '';
constructor(private http: HttpClient, private storageService: StorageService) {
constructor(private envService: EnvironmentService, private http: HttpClient, private storageService: StorageService) {
const aT = this.storageService.getItem(accessTokenStorageKey);
if (aT) {
this.accessToken = aT;
}
this.serviceUrl = this.getServiceUrl();
}
private async getServiceUrl(): Promise<string> {
const url = await lastValueFrom(this.http.get('./assets/environment.json'))
.then((data: any) => {
if (data && data.api) {
return data.api;
}
})
.catch((error) => {
console.error(error);
});
return url;
}
public upload(endpoint: AssetEndpoint | string, body: any, orgId?: string): Promise<any> {
const headers: any = {
[authorizationKey]: `${bearerPrefix} ${this.accessToken}`,
};
if (orgId) {
headers[orgKey] = `${orgId}`;
}
return this.serviceUrl.then((url) =>
this.http
.post(`${url}/assets/v1/${endpoint}`, body, {
return this.envService.env
.pipe(
switchMap((env) =>
this.http.post(`${env.api}/assets/v1/${endpoint}`, body, {
headers: headers,
})
.toPromise(),
);
}),
),
)
.toPromise();
}
}

View File

@ -35,10 +35,8 @@ export class AuthenticationService {
Object.assign(this.authConfig, partialConfig);
}
this.oauthService.configure(this.authConfig);
this.oauthService.strictDiscoveryDocumentValidation = false;
await this.oauthService.loadDiscoveryDocumentAndTryLogin();
this._authenticated = this.oauthService.hasValidAccessToken();
if (!this.oauthService.hasValidIdToken() || !this.authenticated || partialConfig || force) {
const newState = await lastValueFrom(this.statehandler.createState());

View File

@ -0,0 +1,88 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { catchError, map, Observable, of, shareReplay, switchMap, throwError } from 'rxjs';
import { AdminServiceClient } from '../proto/generated/zitadel/AdminServiceClientPb';
import { AuthServiceClient } from '../proto/generated/zitadel/AuthServiceClientPb';
import { ManagementServiceClient } from '../proto/generated/zitadel/ManagementServiceClientPb';
import { ExhaustedService } from './exhausted.service';
export interface Environment {
api: string;
clientid: string;
issuer: string;
customer_portal?: string;
instance_management_url?: string;
exhausted?: boolean;
}
interface WellKnown {
authorization_endpoint: string;
end_session_endpoint: string;
introspection_endpoint: string;
token_endpoint: string;
userinfo_endpoint: string;
}
@Injectable({
providedIn: 'root',
})
export class EnvironmentService {
private environmentJsonPath = './assets/environment.json';
private wellknownPath = '/.well-known/openid-configuration`';
public auth!: AuthServiceClient;
public mgmt!: ManagementServiceClient;
public admin!: AdminServiceClient;
private environment$: Observable<Environment>;
private wellKnown$: Observable<WellKnown>;
constructor(private http: HttpClient, private exhaustedSvc: ExhaustedService) {
this.environment$ = this.createEnvironment();
this.wellKnown$ = this.createWellKnown(this.environment$);
}
// env returns an `Observable<Environment>` that can be subscribed to whenever needed.
// It makes the HTTP call exactly once and replays the cached result.
// If the responses exhausted property is true, the exhaused dialog is shown.
get env() {
return this.environment$;
}
// wellKnown returns an `Observable<Environment>` that can be subscribed to whenever needed.
// It makes the HTTP call exactly once and replays the cached result.
get wellKnown() {
return this.wellKnown$;
}
private createEnvironment() {
return this.http.get<Environment>(this.environmentJsonPath).pipe(
catchError((err) => {
console.error('Getting environment.json failed', err);
return throwError(() => err);
}),
switchMap((env) => {
const env$ = of(env);
if (env.exhausted) {
return this.exhaustedSvc.showExhaustedDialog(env$).pipe(map(() => env));
}
return env$;
}),
// Cache the first response, then replay it
shareReplay(1),
);
}
private createWellKnown(environment$: Observable<Environment>) {
return environment$.pipe(
catchError((err) => {
console.error('Getting well-known OIDC configuration failed', err);
return throwError(() => err);
}),
switchMap((env) => {
return this.http.get<WellKnown>(`${env.issuer}${this.wellknownPath}`);
}),
// Cache the first response, then replay it
shareReplay(1),
);
}
}

View File

@ -0,0 +1,41 @@
import { Injectable } from '@angular/core';
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
import { map, Observable, of, switchMap, tap } from 'rxjs';
import { WarnDialogComponent } from '../modules/warn-dialog/warn-dialog.component';
import { Environment } from './environment.service';
@Injectable({
providedIn: 'root',
})
export class ExhaustedService {
private isClosed = true;
constructor(private dialog: MatDialog) {}
public showExhaustedDialog(env$: Observable<Environment>) {
if (!this.isClosed) {
return of(undefined);
}
this.isClosed = false;
return this.dialog
.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.CONTINUE',
titleKey: 'ERRORS.EXHAUSTED.TITLE',
descriptionKey: 'ERRORS.EXHAUSTED.DESCRIPTION',
},
disableClose: true,
width: '400px',
id: 'authenticated-requests-exhausted-dialog',
})
.afterClosed()
.pipe(
switchMap(() => env$),
tap((env) => {
// Just reload if there is no instance management url
location.href = env.instance_management_url || location.href;
}),
map(() => undefined),
);
}
}

View File

@ -1,18 +1,22 @@
import { PlatformLocation } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
import { TranslateService } from '@ngx-translate/core';
import { AuthConfig } from 'angular-oauth2-oidc';
import { catchError, switchMap, tap, throwError } from 'rxjs';
import { AdminServiceClient } from '../proto/generated/zitadel/AdminServiceClientPb';
import { AuthServiceClient } from '../proto/generated/zitadel/AuthServiceClientPb';
import { ManagementServiceClient } from '../proto/generated/zitadel/ManagementServiceClientPb';
import { AuthenticationService } from './authentication.service';
import { EnvironmentService } from './environment.service';
import { ExhaustedService } from './exhausted.service';
import { AuthInterceptor } from './interceptors/auth.interceptor';
import { ExhaustedGrpcInterceptor } from './interceptors/exhausted.grpc.interceptor';
import { I18nInterceptor } from './interceptors/i18n.interceptor';
import { OrgInterceptor } from './interceptors/org.interceptor';
import { StorageService } from './storage.service';
import { ThemeService } from './theme.service';
@Injectable({
providedIn: 'root',
@ -23,22 +27,30 @@ export class GrpcService {
public admin!: AdminServiceClient;
constructor(
private http: HttpClient,
private envService: EnvironmentService,
private platformLocation: PlatformLocation,
private authenticationService: AuthenticationService,
private storageService: StorageService,
private dialog: MatDialog,
private translate: TranslateService,
private exhaustedService: ExhaustedService,
private themeService: ThemeService,
) {}
public async loadAppEnvironment(): Promise<any> {
return this.http
.get('./assets/environment.json')
.toPromise()
.then((data: any) => {
if (data && data.api && data.issuer) {
public loadAppEnvironment(): Promise<any> {
this.themeService.applyLabelPolicy();
// We use the browser language until we can make API requests to get the users configured language.
return this.translate
.use(this.translate.getBrowserLang() || this.translate.defaultLang)
.pipe(
switchMap(() => this.envService.env),
tap((env) => {
if (!env?.api || !env?.issuer) {
return;
}
const interceptors = {
unaryInterceptors: [
new ExhaustedGrpcInterceptor(this.exhaustedService, this.envService),
new OrgInterceptor(this.storageService),
new AuthInterceptor(this.authenticationService, this.storageService, this.dialog),
new I18nInterceptor(this.translate),
@ -46,19 +58,19 @@ export class GrpcService {
};
this.auth = new AuthServiceClient(
data.api,
env.api,
null,
// @ts-ignore
interceptors,
);
this.mgmt = new ManagementServiceClient(
data.api,
env.api,
null,
// @ts-ignore
interceptors,
);
this.admin = new AdminServiceClient(
data.api,
env.api,
null,
// @ts-ignore
interceptors,
@ -68,19 +80,20 @@ export class GrpcService {
scope: 'openid profile email',
responseType: 'code',
oidc: true,
clientId: data.clientid,
issuer: data.issuer,
clientId: env.clientid,
issuer: env.issuer,
redirectUri: window.location.origin + this.platformLocation.getBaseHrefFromDOM() + 'auth/callback',
postLogoutRedirectUri: window.location.origin + this.platformLocation.getBaseHrefFromDOM() + 'signedout',
requireHttps: false,
};
this.authenticationService.initConfig(authConfig);
}
return Promise.resolve(data);
})
.catch(() => {
console.error('Failed to load environment from assets');
});
}),
catchError((err) => {
console.error('Failed to load environment from assets', err);
return throwError(() => err);
}),
)
.toPromise();
}
}

View File

@ -43,7 +43,7 @@ export class AuthInterceptor<TReq = unknown, TResp = unknown> implements UnaryIn
.then((response: any) => {
return response;
})
.catch((error: any) => {
.catch(async (error: any) => {
if (error.code === 16) {
this.triggerDialog.next(true);
}

View File

@ -0,0 +1,29 @@
import { Injectable } from '@angular/core';
import { Request, StatusCode, UnaryInterceptor, UnaryResponse } from 'grpc-web';
import { EnvironmentService } from '../environment.service';
import { ExhaustedService } from '../exhausted.service';
/**
* ExhaustedGrpcInterceptor shows the exhausted dialog after receiving a gRPC response status 8.
*/
@Injectable({ providedIn: 'root' })
export class ExhaustedGrpcInterceptor<TReq = unknown, TResp = unknown> implements UnaryInterceptor<TReq, TResp> {
constructor(private exhaustedSvc: ExhaustedService, private envSvc: EnvironmentService) {}
public async intercept(
request: Request<TReq, TResp>,
invoker: (request: Request<TReq, TResp>) => Promise<UnaryResponse<TReq, TResp>>,
): Promise<UnaryResponse<TReq, TResp>> {
return invoker(request).catch((error: any) => {
if (error.code === StatusCode.RESOURCE_EXHAUSTED) {
return this.exhaustedSvc
.showExhaustedDialog(this.envSvc.env)
.toPromise()
.then(() => {
throw error;
});
}
throw error;
});
}
}

View File

@ -0,0 +1,24 @@
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { catchError, Observable, switchMap, throwError } from 'rxjs';
import { EnvironmentService } from '../environment.service';
import { ExhaustedService } from '../exhausted.service';
/**
* ExhaustedHttpInterceptor shows the exhausted dialog after receiving an HTTP response status 429.
*/
@Injectable()
export class ExhaustedHttpInterceptor implements HttpInterceptor {
constructor(private exhaustedSvc: ExhaustedService, private envSvc: EnvironmentService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 429) {
return this.exhaustedSvc.showExhaustedDialog(this.envSvc.env).pipe(switchMap(() => throwError(() => error)));
}
return throwError(() => error);
}),
);
}
}

View File

@ -1,43 +0,0 @@
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { OAuthModuleConfig } from 'angular-oauth2-oidc';
import { Observable } from 'rxjs';
import { Org } from '../../proto/generated/zitadel/org_pb';
import { StorageKey, StorageLocation, StorageService } from '../storage.service';
const orgKey = 'x-zitadel-orgid';
export abstract class HttpOrgInterceptor implements HttpInterceptor {
private org!: Org.AsObject;
protected get validUrls(): string[] {
return this.oauthModuleConfig.resourceServer.allowedUrls || [];
}
constructor(private storageService: StorageService, protected oauthModuleConfig: OAuthModuleConfig) {
const org: Org.AsObject | null = this.storageService.getItem(StorageKey.organization, StorageLocation.session);
if (org) {
this.org = org;
}
}
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!this.urlValidation(req.url)) {
return next.handle(req);
}
return next.handle(
req.clone({
setHeaders: {
[orgKey]: this.org.id,
},
}),
);
}
private urlValidation(toIntercept: string): boolean {
const URLS = ['https://api.zitadel.dev/assets', 'https://api.zitadel.ch/assets'];
return URLS.findIndex((url) => toIntercept.startsWith(url)) > -1;
}
}

View File

@ -252,6 +252,10 @@
"TITLE": "Du bist abgemeldet",
"DESCRIPTION": "Klicke auf \"Einloggen\", um Dich erneut anzumelden."
},
"EXHAUSTED": {
"TITLE": "Dein Kontingent an authentifizierten Anfragen is erschöpft.",
"DESCRIPTION": "Lösche oder erhöhe die Grenze für diese ZITADEL Instanz."
},
"INVALID_FORMAT": "Das Format is ungültig.",
"NOTANEMAIL": "Der eingegebene Wert ist keine E-Mail Adresse.",
"MINLENGTH": "Muss mindestens {{requiredLength}} Zeichen lang sein.",

View File

@ -253,6 +253,10 @@
"TITLE": "Your authorization token has expired.",
"DESCRIPTION": "Click the button below to log in again."
},
"EXHAUSTED": {
"TITLE": "Your quota for authenticated requests is exhausted.",
"DESCRIPTION": "Remove or increase the quota limit for this ZITADEL instance."
},
"INVALID_FORMAT": "The formatting is invalid.",
"NOTANEMAIL": "The given value is not an e-mail address.",
"MINLENGTH": "Must be at least {{requiredLength}} characters long.",

View File

@ -253,6 +253,10 @@
"TITLE": "Tu token de autorización token ha caducado.",
"DESCRIPTION": "Haz clic en el botón más abajo para iniciar sesión otra vez."
},
"EXHAUSTED": {
"TITLE": "Su cuota de solicitudes autenticadas se ha agotado.",
"DESCRIPTION": "Borrar o aumentar el límite de esta instancia de ZITADEL."
},
"INVALID_FORMAT": "El formato no es valido.",
"NOTANEMAIL": "El valor proporcionado no es una dirección de email.",
"MINLENGTH": "Debe tener al menos {{requiredLength}} caracteres de longitud.",

View File

@ -252,6 +252,10 @@
"TITLE": "Votre jeton d'autorisation a expiré.",
"DESCRIPTION": "Cliquez sur le bouton ci-dessous pour vous reconnecter."
},
"EXHAUSTED": {
"TITLE": "Ton quota de demandes authentifiées est épuisé.",
"DESCRIPTION": "Supprimez ou augmentez la limite de cette instance ZITADEL."
},
"INVALID_FORMAT": "Le format n'est pas valide",
"NOTANEMAIL": "La valeur donnée n'est pas une adresse e-mail",
"MINLENGTH": "Doit comporter au moins {{length}} caractères.",

View File

@ -252,6 +252,10 @@
"TITLE": "Il tuo Access Token \u00e8 scaduto.",
"DESCRIPTION": "Clicca il pulsante per richiedere una nuova sessione."
},
"EXHAUSTED": {
"TITLE": "La quota di richieste autenticate è esaurita.",
"DESCRIPTION": "Cancellare o aumentare il limite per questa istanza ZITADEL."
},
"INVALID_FORMAT": "Il formato non è valido.",
"NOTANEMAIL": "Il valore dato non \u00e8 un indirizzo e-mail.",
"MINLENGTH": "Deve essere lunga almeno {{requiredLength}} caratteri.",

View File

@ -253,6 +253,10 @@
"TITLE": "トークンが期限切れになりました。",
"DESCRIPTION": "下のボタンをクリックして、もう一度ログインする。"
},
"EXHAUSTED": {
"TITLE": "認証されたリクエストのクォータを使い果たしました",
"DESCRIPTION": "このZITADELインスタンスの制限を削除または増加させる"
},
"INVALID_FORMAT": "不正なフォーマットです",
"NOTANEMAIL": "入力された値がメールアドレスではありません。",
"MINLENGTH": "{{requiredLength}} 文字以上の文字列が必要です。",

View File

@ -252,6 +252,10 @@
"TITLE": "Twój token autoryzacji wygasł.",
"DESCRIPTION": "Kliknij przycisk poniżej, aby ponownie się zalogować."
},
"EXHAUSTED": {
"TITLE": "Twój limit uwierzytelnionych wniosków został wyczerpany.",
"DESCRIPTION": "Usuń lub zwiększ limit dla tej instancji ZITADEL."
},
"INVALID_FORMAT": "Format jest nieprawidłowy.",
"NOTANEMAIL": "Podana wartość nie jest adresem e-mail.",
"MINLENGTH": "Musi mieć co najmniej {{requiredLength}} znaków.",

View File

@ -252,6 +252,10 @@
"TITLE": "您的授权令牌已过期。",
"DESCRIPTION": "点击下方按钮再次登录。"
},
"EXHAUSTED": {
"TITLE": "你的认证请求配额已用完.",
"DESCRIPTION": "删除或增加这个ZITADEL实例的限制。"
},
"INVALID_FORMAT": "格式是无效的。",
"NOTANEMAIL": "给定的值不是合法电子邮件地址。",
"MINLENGTH": "长度必须至少是{{requiredLength}}字符。",

3
docs/.gitignore vendored
View File

@ -9,6 +9,9 @@
.cache-loader
.artifacts
# Generated by docusaurus-plugin-openapi-docs
docs/apis/resources
# Misc
.DS_Store
.env.local

View File

@ -1,5 +1,6 @@
---
title: Overview
title: API Reference Overview
sidebar_label: Overview
---
import { ApiCard } from "../../src/components/apicard";
@ -50,7 +51,7 @@ Endpoint:
$ZITADEL_DOMAIN/auth/v1/
API Reference:
[OpenAPI Docs](/apis/auth)
[OpenAPI Docs](/apis/resources/auth)
</div>
</Column>
@ -83,7 +84,7 @@ Endpoint:
$ZITADEL_DOMAIN/management/v1/
API Reference:
[OpenAPI Docs](/apis/mgmt)
[OpenAPI Docs](/apis/resources/mgmt)
</div>
</Column>
@ -114,7 +115,7 @@ Endpoint:
$ZITADEL_DOMAIN/admin/v1/
API Reference:
[OpenAPI Docs](/apis/admin)
[OpenAPI Docs](/apis/resources/admin)
</div>
</Column>
@ -147,7 +148,7 @@ Endpoint:
$ZITADEL_DOMAIN/system/v1/
API Reference:
[OpenAPI Docs](/apis/system)
[OpenAPI Docs](/apis/resources/system)
</div>
</Column>

View File

@ -145,4 +145,7 @@ The storage layer of ZITADEL is responsible for multiple things. For example:
- Backup and restore operation for disaster recovery purpose
ZITADEL currently supports CockroachDB as first choice of storage due to its perfect match for ZITADELs needs.
PostgreSQL support is currently in beta.
Postgres is currently in [Beta](/docs/support/software-release-cycles-support#beta) and will be [Enterprise Supported](/docs/support/software-release-cycles-support#partially-supported) afterwards.
Beta state will be removed as soon as [automated tests](https://github.com/zitadel/zitadel/issues/5741) are implemented.
Make sure to read our [Production Guide](./self-hosting/manage/production#prefer-cockroachdb) before you decide to use it.

View File

@ -9,8 +9,9 @@ Since the storage layer takes the heavy lifting of making sure that data in sync
Depending on your projects needs our general recommendation is to run ZITADEL and ZITADELs storage layer across multiple availability zones in the same region or if you need higher guarantees run the storage layer across multiple regions.
Consult the [CockroachDB documentation](https://www.cockroachlabs.com/docs/) for more details or use the [CockroachCloud Service](https://www.cockroachlabs.com/docs/cockroachcloud/create-an-account.html)
> Postgres support of ZITADEL is currently in beta.
Postgres is currently in [Beta](/docs/support/software-release-cycles-support#beta) and will be [Enterprise Supported](/docs/support/software-release-cycles-support#partially-supported) afterwards.
Beta state will be removed as soon as [automated tests](https://github.com/zitadel/zitadel/issues/5741) are implemented.
Make sure to read our [Production Guide](./self-hosting/manage/production#prefer-cockroachdb) before you decide to use it.
## Scalability

View File

@ -1,5 +1,6 @@
---
title: Overview
title: Eventstore
sidebar_label: Overview
---
ZITADEL is built on the [Event Sourcing pattern](../architecture/software), where changes are stored as events in an Event Store.

View File

@ -35,7 +35,7 @@ Go to your instance settings and then click on the Tab **Events** to open the Ev
Since everything that is available in Console can also be called with our APIs, you can access all events and audit data trough our APIs:
- [Event API Guide](/docs/guides/integrate/event-api)
- [API Documentation](/docs/category/apis/admin/events)
- [API Documentation](/docs/category/apis/resources/admin/events)
Access to the API is possible with a [Service User](/docs/guides/integrate/serviceusers) account, allowing you to integrate the events with your own business logic.

View File

@ -151,7 +151,7 @@ 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, SMS)
- Mobile one-time password (OTP) (Authenticator Apps)
- FIDO Universal Second Factor (U2F) (Security Keys, Device, etc.)
- FIDO2 WebAuthN (Passkeys)

View File

@ -1,10 +0,0 @@
---
title: Introduction
---
This part of the **ZITADEL** documentation contains ZITADEL specific or general concepts required to understand the system or our guides.
![Overview](/img/concepts/objects/object_overview.png)
This overview shows the general structure of ZITADEL.
You will find more detailed explanations around the different concepts in the following sections.

View File

@ -14,13 +14,18 @@ which in turn can represent your own company (e.g. departments), your business c
Read more about how to configure your instance in our [instance guide](/guides/manage/console/instance-settings).
![Two instances with each organizations in it using the same database](/img/concepts/objects/instances.png)
![Overview](/img/concepts/objects/object_overview.png)
This overview shows the general structure of ZITADEL.
You will find more detailed explanations around the different concepts in the following sections.
## Multiple Virtual Instances
ZITADEL has the concept of virtual instances.
When installing ZITADEL from scratch, one instance is always automatically created for you.
Nevertheless, you can add more virtual instances via the [system API](/apis/system).
Nevertheless, you can add more virtual instances via the [system API](/apis/resources/system).
This is useful if you have business customers, which in turn have their business customers with self service and custom domain demands.
By providing a virtual ZITADEL instances, your customers have all the customization options available in ZITADEL.
Scaling ZITADEL instances virtually enables you to easily distribute your limited compute resources to all your customers.
![Two instances with each organizations in it using the same database](/img/concepts/objects/instances.png)

View File

@ -1,17 +0,0 @@
---
title: Overview
---
This overview shows the general structure of ZITADEL.
![Overview](/img/concepts/objects/object_overview.png)
More details on the specific objects:
- [Instance](./instance)
- [Organizations](./organizations)
- [Policies/Settings](./policies)
- [Projects](./projects)
- [Applications](./applications)
- [Granted Projects](./granted_projects)
- [Users](./users)

View File

@ -1,12 +1,13 @@
---
title: Overview
title: Overview of examples, quickstarts, and SDKs
sidebar_label: Overview
---
Our examples cover a range of programming languages and frameworks, so no matter what you're into, we've got you covered.
## Frontend
### Single Page Application
### Single page application
<table>
<tr>
@ -45,7 +46,7 @@ Our examples cover a range of programming languages and frameworks, so no matter
</tr>
</table>
### Native / Mobile App
### Native/mobile app
<table>
<tr>
@ -66,7 +67,7 @@ Our examples cover a range of programming languages and frameworks, so no matter
</tr>
</table>
### Regular Web App
### Regular web app
<table>
<tr>

View File

@ -2,50 +2,51 @@
title: Angular
---
This integration guide shows you the recommended way to integrate ZITADEL into your Angular application.
It shows how to add user login to your application and fetch some data from the user info endpoint.
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Angular application.
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
At the end of the guide, your application has login functionality and has access to the current user's profile.
By the end of this guide, your application will have login functionality and will be able to access the current user's profile.
> This documentation refers to our [example](https://github.com/zitadel/zitadel-angular) in GitHub. Note that we've written ZITADEL Console in Angular, so you can also use that as a reference.
> This documentation references our [example](https://github.com/zitadel/zitadel-angular) on GitHub. Please note that we wrote the ZITADEL Console in Angular, so you can also use that as a reference.
## Setup Application and Get Keys
## Set up application and obtain keys
Before we can start building our application, we have to do a few configuration steps in ZITADEL Console.
You will need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
Select **User Agent** application type and continue.
We recommend you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all SPA applications.
Before we begin developing our application, we need to perform a few configuration steps in the ZITADEL Console.
You'll need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
Select the **User Agent** application type and continue.
We recommend that you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all SPA applications.
![Create app in console](/img/angular/app-create.png)
### Redirect URIs
With the Redirect URIs field, you tell ZITADEL where it is allowed to redirect users to after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
The Post logout redirect send the users back to a route on your application after they have logged out.
The Redirect URIs field tells ZITADEL where it's allowed to redirect users after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
The Post-logout redirect send the users back to a route on your application after they have logged out.
> If you are following along with the [example](https://github.com/zitadel/zitadel-angular), set dev mode to `true`, the Redirect URIs to <http://localhost:4200/auth/callback> and Post redirect URI to <http://localhost:4200/signedout>.
> If you are following along with the [example](https://github.com/zitadel/zitadel-angular), set the dev mode to `true`, the Redirect URIs to <http://localhost:4200/auth/callback> and Post redirect URI to <http://localhost:4200/signedout>.
Continue and create the application.
### Client ID
After successful app creation, a pop-up will appear, showing the app's client ID. Copy the client ID, as you will need it to configure your Angular client.
After successful creation of the app, a pop-up will appear displaying the app's client ID. Copy the client ID, as you will need it to configure your Angular client.
## Angular Setup
## Angular setup
Now that you have your web application configured on the ZITADEL side, you can go ahead and integrate your Angular client.
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Angular client.
### Install Angular Dependencies
### Install Angular dependencies
You need to install an OAuth / OIDC client to connect with ZITADEL. Run the following command:
To connect with ZITADEL, you need to install an OAuth/OIDC client. Run the following command:
```bash
npm install angular-oauth2-oidc
```
### Create and Configure Auth Module
### Create and configure the auth module
Add _OAuthModule_ to your Angular imports in _AppModule_ and provide the _AuthConfig_ in the providers' section. Also, ensure you import the _HTTPClientModule_.
Add _OAuthModule_ to your Angular imports in _AppModule_ and provide the _AuthConfig_ in the providers' section. Also, ensure that you import the _HTTPClientModule_.
```ts reference
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app.module.ts
@ -59,20 +60,18 @@ You can use Angulars schematics to do so:
ng g service services/authentication
```
Copy the following code to your service. This code provides a function `authenticate()` which redirects the user to ZITADEL. After successful login, ZITADEL redirects the user back to the redirect URI configured in _AuthModule_ and ZITADEL Console. Make sure both correspond, otherwise ZITADEL throws an error.
Copy the following code to your service. This code provides a function `authenticate()`, which redirects the user to ZITADEL. After a successful login, ZITADEL redirects the user back to the redirect URI configured in _AuthModule_ and ZITADEL Console. Ensure that both correspond, otherwise ZITADEL will throw an error.
```ts reference
https://github.com/zitadel/zitadel-angular/blob/main/src/app/services/authentication.service.ts
```
Our example includes a _StatehandlerService_ to redirect the user back to the route where he initially came from.
If you don't need such behavior, you can omit the following line from the `authenticate()` method above.
Our example includes a _StatehandlerService_ that redirects the user back to the route from which they initially came.If you don't need such behavior, you can omit the following line from the `authenticate()` method above.
```ts reference
https://github.com/zitadel/zitadel-angular/blob/main/src/app/services/authentication.service.ts#L45
```
If you decide to use the _StatehandlerService_, provide it in the `app.module`. Make sure it gets initialized first using Angulars `APP_INITIALIZER`. You find the service implementation in the [example](https://github.com/zitadel/zitadel-angular).
If you decide to use the _StatehandlerService_, include it in the `app.module`. Ensure it gets initialized first using Angulars `APP_INITIALIZER`. You can find the service implementation in the [example](https://github.com/zitadel/zitadel-angular).
```ts reference
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app.module.ts#L26-L30
@ -82,15 +81,14 @@ https://github.com/zitadel/zitadel-angular/blob/main/src/app/app.module.ts#L26-L
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app.module.ts#L55-L78
```
### Add Login to Your Application
### Add login to your application
To log a user in, you need a component or a guard.
To log in a user, you need a component or a guard.
- A component could provide a button, starting the login flow on click.
- A component could provide a button that initiates the login flow when clicked.
- A guard initiates a login flow when a user without a stored valid access token attempts to access a protected route.
- A guard that starts a login flow once a user without a stored valid access token tries to access a protected route.
Using these components heavily depends on your application. In most cases, you need both.
The use of these components depends heavily on your application. In most cases, you need both.
Generate a component like this:
@ -100,8 +98,7 @@ ng g component components/login
Inject the _AuthenticationService_ and call `authenticate()` on some click event.
Same for the guard:
Do the same for the guard:
```bash
ng g guard guards/auth
```
@ -118,23 +115,23 @@ Add the guard to your _RouterModule_ similar to this:
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app-routing.module.ts#L9-L31
```
> Note: Make sure you redirect the user from your callback URL to a guarded page, so `authenticate()` is called again and the access token is stored.
> Note: Make sure you redirect the user from your callback URL to a guarded page, so the `authenticate()` method is called again, and the access token is stored.
```ts reference
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app-routing.module.ts#L19-L21
```
### Add Logout to Your Application
### Add logout to your application
Call `auth.signout()` for logging the current user out. Note that you can also configure a logout redirect URI if you want your users to be redirected after logout.
Call `auth.signout()` to log out the current user. Keep in mind that you can also configure a logout redirect URI if you want your users to be redirected after logout.
```ts reference
https://github.com/zitadel/zitadel-angular/blob/main/src/app/components/user/user.component.ts#L20-L22
```
### Show User Information
### Display user information
To fetch user data, ZITADEL's user info endpoint has to be called. This data contains sensitive information and artifacts related to the current user's identity and the scopes you defined in your _AuthConfig_.
To fetch user data, you need to call the ZITADEL's user info endpoint. This data contains sensitive information and artifacts related to the current user's identity and the scopes you defined in your _AuthConfig_.
Our _AuthenticationService_ already includes a method called _getOIDCUser()_. You can call it wherever you need this information.
```ts reference
@ -149,25 +146,26 @@ https://github.com/zitadel/zitadel-angular/blob/main/src/app/components/user/use
### Refresh token
If you want to add a refresh token to your application you have to navigate to the console application and tick the checkbox in the configuration section.
Then add `offline_access` to the scopes and add the line
If you want to add a refresh token to your application, navigate to the console application and check the box in the configuration section.
Then add `offline_access` to the scopes and add the following line:
```
this.oauthService.setupAutomaticSilentRefresh();
```
this will automatically refresh a token before it expires.
This line automatically refreshes a token before it expires.
## Completion
You have successfully integrated your Angular application with ZITADEL!
Congratulations! You have successfully integrated your Angular application with ZITADEL!
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-angular) application. It includes all the mentioned functionality of this quickstart. You can simply start by cloning the repository and replacing the _AuthConfig_ in the _AppModule_ by your own configuration. If you run into issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/zitadel).
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-angular) application. This application includes all the funcationalities mentioned in this quickstart. You can start by cloning the repository and replacing the _AuthConfig_ in the _AppModule_ with your own configuration. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/zitadel).
![App in console](/img/angular/app-screen.png)
### What's next?
Now that you have enabled authentication, it's time to add authorization to your application using ZITADEL APIs. Refer to the [docs](/apis/introduction) or check out our ZITADEL Console code on [GitHub](https://github.com/zitadel/zitadel) which is using gRPC to access data.
Now that you have enabled authentication, it's time for you to add authorization to your application using ZITADEL APIs. To do this, you can refer to the [docs](/apis/introduction) or check out the ZITADEL Console code on [GitHub](https://github.com/zitadel/zitadel) which uses gRPC to access data.
For more information about creating an Angular application, refer to [Angular](https://angular.io/start) and for more information about the OAuth/OIDC library used above, consider reading their docs at [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc).
For more information on how to create an Angular application, you can refer to [Angular](https://angular.io/start). If you want to learn more about the OAuth/OIDC library used above, consider reading the docs at [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc).

View File

@ -13,6 +13,71 @@ title: SDKs
| Python | 🚧 [WIP](https://github.com/zitadel/zitadel/issues/3675) | ❓ | ❓ | TBD |
| NodeJS | [@zitadel/node](https://www.npmjs.com/package/@zitadel/node) | ❌ | ✔️ | `community` |
## Missing an SDK
Is your language/framework missing? Fear not, you can generate your gRPC API Client with ease.
1. Make sure to install [buf](https://buf.build/docs/installation/)
2. Create a `buf.gen.yaml` and configure the [plugins](https://buf.build/plugins) you need
3. Run `buf generate https://github.com/zitadel/zitadel#format=git,tag=v2.23.1` (change the versions to your needs)
Let us make an example with Ruby. Any other supported language by buf will work as well. Consult the [buf plugin registry](https://buf.build/plugins) for more ideas.
### Example with Ruby
With gRPC we usually need to generate the client stub and the messages/types. This is why we need two plugins.
The plugin `grpc/ruby` generates the client stub and the plugin `protocolbuffers/ruby` takes care of the messages/types.
```yaml
version: v1
plugins:
- plugin: buf.build/grpc/ruby
out: gen
- plugin: buf.build/protocolbuffers/ruby
out: gen
```
If you now run `buf generate https://github.com/zitadel/zitadel#format=git,tag=v2.23.1` in the folder where your `buf.gen.yaml` is located you should see the folder `gen` appear.
If you run `ls -la gen/zitadel/` you should see something like this:
```bash
ffo@ffo-pc:~/git/zitadel/ruby$ ls -la gen/zitadel/
total 704
drwxr-xr-x 2 ffo ffo 4096 Apr 11 16:49 .
drwxr-xr-x 3 ffo ffo 4096 Apr 11 16:49 ..
-rw-r--r-- 1 ffo ffo 4397 Apr 11 16:49 action_pb.rb
-rw-r--r-- 1 ffo ffo 141097 Apr 11 16:49 admin_pb.rb
-rw-r--r-- 1 ffo ffo 25151 Apr 11 16:49 admin_services_pb.rb
-rw-r--r-- 1 ffo ffo 6537 Apr 11 16:49 app_pb.rb
-rw-r--r-- 1 ffo ffo 1134 Apr 11 16:49 auth_n_key_pb.rb
-rw-r--r-- 1 ffo ffo 32881 Apr 11 16:49 auth_pb.rb
-rw-r--r-- 1 ffo ffo 6896 Apr 11 16:49 auth_services_pb.rb
-rw-r--r-- 1 ffo ffo 1571 Apr 11 16:49 change_pb.rb
-rw-r--r-- 1 ffo ffo 2488 Apr 11 16:49 event_pb.rb
-rw-r--r-- 1 ffo ffo 14782 Apr 11 16:49 idp_pb.rb
-rw-r--r-- 1 ffo ffo 5031 Apr 11 16:49 instance_pb.rb
-rw-r--r-- 1 ffo ffo 223348 Apr 11 16:49 management_pb.rb
-rw-r--r-- 1 ffo ffo 44402 Apr 11 16:49 management_services_pb.rb
-rw-r--r-- 1 ffo ffo 3020 Apr 11 16:49 member_pb.rb
-rw-r--r-- 1 ffo ffo 855 Apr 11 16:49 message_pb.rb
-rw-r--r-- 1 ffo ffo 1445 Apr 11 16:49 metadata_pb.rb
-rw-r--r-- 1 ffo ffo 2370 Apr 11 16:49 object_pb.rb
-rw-r--r-- 1 ffo ffo 621 Apr 11 16:49 options_pb.rb
-rw-r--r-- 1 ffo ffo 4425 Apr 11 16:49 org_pb.rb
-rw-r--r-- 1 ffo ffo 8538 Apr 11 16:49 policy_pb.rb
-rw-r--r-- 1 ffo ffo 8223 Apr 11 16:49 project_pb.rb
-rw-r--r-- 1 ffo ffo 1022 Apr 11 16:49 quota_pb.rb
-rw-r--r-- 1 ffo ffo 5872 Apr 11 16:49 settings_pb.rb
-rw-r--r-- 1 ffo ffo 20985 Apr 11 16:49 system_pb.rb
-rw-r--r-- 1 ffo ffo 4784 Apr 11 16:49 system_services_pb.rb
-rw-r--r-- 1 ffo ffo 28759 Apr 11 16:49 text_pb.rb
-rw-r--r-- 1 ffo ffo 24170 Apr 11 16:49 user_pb.rb
-rw-r--r-- 1 ffo ffo 13568 Apr 11 16:49 v1_pb.rb
```
Import these files into your project to start interacting with ZITADEL's APIs.
## More
While we are not actively maintaining the following projects, it is worth checking out if you're interested in exploring ZITADEL in different programming languages or frameworks.

View File

@ -145,7 +145,7 @@ You should get a successful response with a `totalResult` number of 1 and the de
}
```
With this token you are allowed to access the whole [ZITADEL System API](/apis/system).
With this token you are allowed to access the whole [ZITADEL System API](/apis/resources/system).
## Summary

View File

@ -11,7 +11,7 @@ You need to give a user the [manager role](https://zitadel.com/docs/guides/manag
If you like to know more about eventsourcing/eventstore and how this works in ZITADEL, head over to our [concepts](../../concepts/eventstore/overview).
## Request Events
Call the [ListEvents](/apis/admin) enpoint in the Administration API to get all the events you need.
Call the [ListEvents](/apis/resources/admin) enpoint in the Administration API to get all the events you need.
To further restrict your result you can add the following filters:
- sequence
- editor user id
@ -29,7 +29,7 @@ curl --request POST \
## Get event types
To be able to filter for the different event types ZITADEL knows, you can request the [EventTypesList](/apis/admin)
To be able to filter for the different event types ZITADEL knows, you can request the [EventTypesList](/apis/resources/admin)
```bash
curl --request POST \
@ -65,7 +65,7 @@ The following example shows you the event types for a password check (failed/suc
## Get aggregate types
To be able to filter for the different aggregate types (resources) ZITADEL knows, you can request the [AggregateTypesList](/apis/admin)
To be able to filter for the different aggregate types (resources) ZITADEL knows, you can request the [AggregateTypesList](/apis/resources/admin)
```bash
curl --request POST \

View File

@ -15,7 +15,7 @@ This is a guide on how to create service users in ZITADEL. You can read more abo
In ZITADEL we use the `urn:ietf:params:oauth:grant-type:jwt-bearer` (**“JWT bearer token with private key”**, [RFC7523](https://tools.ietf.org/html/rfc7523)) authorization grant for this non-interactive authentication.
You need to follow these steps to authenticate a service user and receive a access token:
You need to follow these steps to authenticate a service user and receive an access token:
1. Generate a private-public key pair in ZITADEL
2. Create a JSON Web Token (JWT) and sign with private key
@ -25,7 +25,7 @@ With this token you can make subsequent requests, just like a human user.
## Get an access token
In this step we will authenticate a service user and receive an access_token to use against a API.
In this step we will authenticate a service user and receive an access_token to use against the API.
> **Information:** Are you stuck? Don't hesitate to reach out to us on [Github Discussions](https://github.com/zitadel/zitadel/discussions) or [contact us](https://zitadel.com/contact/) privately.
@ -96,6 +96,8 @@ curl --request POST \
--data assertion=eyJ0eXAiOiJKV1QiL...
```
If you want to access the ZITADEL API with this access token, you have to add `urn:zitadel:iam:org:project:id:zitadel:aud` to the list of scopes.
* `grant_type` should be set to `urn:ietf:params:oauth:grant-type:jwt-bearer`
* `scope` should contain any [Scopes](/apis/openidoauth/scopes) you want to include, but must include `openid`. For this example, please include `profile` and `email`
* `assertion` is the encoded value of the JWT that was signed with your private key from the prior step

View File

@ -1,14 +0,0 @@
---
title: Overview
---
The ZITADEL customer Portal is used to manage all your different ZITADEL instances.
You can also manage your subscriptions, billing, newsletters and support requests.
More details on the specific objects:
- [Getting Started](./start)
- [Instances](./instances)
- [Billing](./billing)
- [Users](./users)
- [Support](./support)

View File

@ -2,6 +2,9 @@
title: Support
---
:::note
We describe our [support services](/docs/legal/support-services) and information required in more detail in our legal section. Beware that not all features may be supported by your subscription and consult the [support states](/docs/support/software-release-cycles-support#support-states).
:::
In the header you can find a button for the support.
Create a new support request with the following information:

View File

@ -1,5 +1,6 @@
---
title: Overview
title: Console
sidebar_label: Overview
---
## What is console?

View File

@ -5,6 +5,7 @@ title: Customized Texts
You are able to customize the texts used from ZITADEL. This is possibly on the instance or organization level.
## Message Texts
Sometimes the users will get an email or phone message from ZITADEL (e.g Password Reset Request).
ZITADEL already has some good standard texts, but maybe you would like to customize it for your organization.
@ -29,7 +30,7 @@ You will see the default texts in the input field and you can overwrite them by
If you don't like your customization anymore click the "reset policy" button.
All your settings will be removed and the default settings of the system will trigger.
## Internationalization
## Internationalization / i18n
ZITADEL is available in the following languages

View File

@ -6,7 +6,7 @@ The ZITADEL API has different possibilities to create users.
This can be used, if you are building your own registration page.
Use the following API call to create your users:
[Create User (Human)](/apis/mgmt/management-service-import-human-user.api.mdx)
[Create User (Human)](/apis/resources/mgmt/management-service-import-human-user.api.mdx)
## With Username and Password
@ -31,7 +31,7 @@ If nothing is requested, the type will not be restricted and all possibilities o
If you already have a user in ZITADEL, it is possible to add passwordless later.
[Add Passwordless Registration ](/apis/mgmt)
[Add Passwordless Registration ](/apis/resources/mgmt)
Send the user_id in the request and you will get a link and an expiration as response.
You can then customize the link the same as described above in the creation process.
@ -39,7 +39,7 @@ You can then customize the link the same as described above in the creation proc
The second possibility is to send the link directly to the user per email.
Use the following request in that case:
[Send Passwordless Registration ](/apis/mgmt)
[Send Passwordless Registration ](/apis/resources/mgmt)
## Verified Email Address

View File

@ -7,7 +7,7 @@ Migrating users from an existing system, while minimizing impact on said users,
## Individual Users
Creating individual users can be done with this endpoint: [ImportHumanUser](/docs/apis/mgmt/management-service-import-human-user).
Creating individual users can be done with this endpoint: [ImportHumanUser](/docs/apis/resources/mgmt/management-service-import-human-user).
Please also consult our [guide](/docs/guides/manage/user/reg-create-user) on how to create users.
```json
@ -42,7 +42,7 @@ Please also consult our [guide](/docs/guides/manage/user/reg-create-user) on how
## Bulk import
For bulk import use the [import endpoint](https://zitadel.com/docs/apis/admin/admin-service-import-data) on the admin API:
For bulk import use the [import endpoint](https://zitadel.com/docs/apis/resources/admin/admin-service-import-data) on the admin API:
```json
{
@ -220,7 +220,7 @@ Use metadata to store additional attributes of the users, such as organizational
:::info
Metadata must be added to users after the users were created. Currently metadata can't be added during user creation.
[API reference: User Metadata](https://zitadel.com/docs/category/apis/mgmt/user-metadata)
[API reference: User Metadata](https://zitadel.com/docs/category/apis/resources/mgmt/user-metadata)
:::
Request metadata from the userinfo endpoint by passing the required [reserved scope](/docs/apis/openidoauth/scopes#reserved-scopes) in your auth request.
@ -232,5 +232,5 @@ You can assign roles from owned or granted projects to a user.
:::info
Authorizations must be added to users after the users were created. Currently metadata can't be added during user creation.
[API reference: User Authorization / Grants](https://zitadel.com/docs/category/apis/auth/user-authorizations-grants)
[API reference: User Authorization / Grants](https://zitadel.com/docs/category/apis/resources/auth/user-authorizations-grants)
:::

View File

@ -1,49 +1,46 @@
---
title: Overview
title: Documentation
sidebar_label: Overview
---
Most applications need to know the identity of a user for access control, to securely store their data in the cloud, and provide the same personalized experience across all of the user's devices.
Most applications require user identity for access control, secure data storage in the cloud, and to provide a consistent, personalized experience across all of a user's devices.
With ZITADEL, you can rely on a hardened and extensible turnkey solution to address all your authentication and authorization needs. We offer a wide range of features out of the box to accelerate your project. These features include multi-tenancy with branding customization, secure login, self-service, OpenID Connect, OAuth2.x, SAML2, Passwordless with FIDO2 (including Passkeys), OTP, U2F, and an unlimited audit trail. Execute custom code on selected events within ZITADEL to ensure compatibility with your unique and complex software landscape and data models.
With ZITADEL you can rely on a hardened and extensible turnkey solution to solve all of your authentication and authorization needs.
We provide you with a wide range of out of the box features to accelerate your project. Multi-tenancy with branding customization, secure login, self-service, OpenID Connect, OAuth2.x, SAML2, Passwordless with FIDO2 (including Passkeys), OTP, U2F, and an unlimited audit trail is there for you, ready to use.
Execute custom code on selected events within ZITADEL to ensure perfect compatibility with your unique and complex software landscape and data models.
## Get started
## Get Started
### Quick start guide
### Quick Start Guide
Follow our [quick start guide](/guides/start/quickstart).
Follow our [Quick Start Guide](/guides/start/quickstart).
### Cloud or self-hosting
### Cloud or Self-Hosting
You can use ZITADEL in two ways:
ZITADEL can be used in two ways:
- ZITADEL Cloud: This is our public cloud service. Use the free tier to start in minutes.
- Self-hosted ZITADEL: For full control, deploy ZITADEL wherever you prefer.
- Use the ZITADEL Cloud, our public cloud service. Use the free tier to get started in minutes.
- Deploy a self-hosted ZITADEL for full control, wherever you like.
If you are unsure, opt for the gracious free tier of [ZITADEL Cloud](./manage/cloud/overview).
If you're unsure, consider the generous free tier of [ZITADEL Cloud](./manage/cloud/overview).
Choose [ZITADEL Cloud](./manage/cloud/overview) if you want:
- A turnkey solution that just works
- A gracious free tier with a great pay-as-you-go option
- Global scalability without the headache of running it yourself
- A turnkey solution that's ready to go- A generous free tier with an excellent pay-as-you-go option
- Global scalability without the hassle of managing it yourself
- Data-residency compliance for your customers
Choose [ZITADEL Self-Hosted](/self-hosting/deploy/overview) if you want:
Choose [ZITADEL self-hosted](/self-hosting/deploy/overview) if you want:
- Total control over all components and your data
- To run ZITADEL in air-gapped or regulated environments
- Flexibility when you deploy updates
- Flexibility when deploying updates
## Get Help
## Get help
Join our [Discord Chat](https://zitadel.com/chat) or open a [Discussion](https://github.com/zitadel/zitadel/discussions) on Github to get help from the community and the team behind ZITADEL.
Join our [Discord chat](https://zitadel.com/chat) or open a [discussion](https://github.com/zitadel/zitadel/discussions) on Github to get help from the community and the ZITADEL team.
Cloud and Enterprise customers can additionally reach us privately via the [Support communication channels](/legal/support-services).
Cloud and enterprise customers can additionally reach us privately via our [support communication channels](/legal/support-services).
## Contribute
ZITADEL is open source — and so is the documentation.
Should you happen to stumble over an incorrectness, a spelling mistake, a hard-to-understand text passage, please dont hesitate to leave a comment or [contribute a corresponding change](https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md).
If you find any inaccuracies, spelling mistakes, or unclear text passages, please don't hesitate to leave a comment or [contribute a corresponding change](https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md).

View File

@ -29,7 +29,7 @@ You can read more about how ZITADEL handles usernames [here](../manage/console/o
ZITADEL gives you a basic storage for users and manages phone and email addresses. It also allows you to store your own application data such as preferences or external identifiers to the metadata of a user.
If you are migrating an existing project and you already have an external identity store you can consider bulk importing your user datasets.
Read our [Management API definitions](/apis/mgmt) for more info. If the users email is not verified or no password is set, a initialization mail will be send.
Read our [Management API definitions](/apis/resources/mgmt) for more info. If the users email is not verified or no password is set, a initialization mail will be send.
:::info
Requests to the management API are rate limited. Read our [Rate limit Policy](../../legal/rate-limit-policy) for more info.

View File

@ -1,5 +1,5 @@
---
title: Quick Start Guide
title: Quick start guide
---
import VSCodeFolderView from "../../../static/img/guides/quickstart/vscode1.png";
@ -12,7 +12,7 @@ In this quick start guide, we will be learning some fundamentals on how to set u
The sample application allows users to securely log in to ZITADEL using the OIDC Proof Key for Code Exchange (PKCE) flow. This flow ensures that the authentication process is secure by using a code verifier and a code challenge, which are sent to ZITADEL to obtain an access token. The access token is then used by the app to access the userinfo endpoint to retrieve and display information about the logged-in user. The app also has a logout feature that allows users to end their session and clear their access token. Overall, the app provides a simple and secure way for users to authenticate and access protected resources within ZITADEL.
## ZITADEL Terminology: Instances, Organizations, Projects, Users, Roles, Authorizations and Apps
## ZITADEL terminology: instances, organizations, projects, users, roles, authorizations and apps
In ZITADEL, instances, organizations, projects, users, roles, and apps are the main components that make up the platform.
@ -31,9 +31,9 @@ The order of creation for the above components would typically be as follows:
The order of creation for the above components may vary depending on the specific needs and requirements of the organization.
## Set Up and Manage ZITADEL for your Identity Projects
## Set up and manage ZITADEL for your identity projects
### 1. Sign up for the ZITADEL Cloud Customer Portal and Register your Organization
### 1. Sign up for the ZITADEL Cloud customer portal and register your organization
1. Go to [zitadel.com](http://zitadel.com) and click on “Start for FREE”.
@ -75,7 +75,7 @@ The order of creation for the above components may vary depending on the specifi
![Create Instance](/img/guides/quickstart/10.png)
### 2. Create your First Instance
### 2. Create your first instance
As a user of the ZITADEL Cloud Customer Portal, you now can create multiple instances to suit your specific needs. This includes instances for development, production, or user acceptance testing, as well as instances for different clients or applications. For example, you might create an instance for each product in a B2C scenario, or an instance for each tenant or customer in a B2B scenario. The possibilities are endless. You can create a pay-as-you-go instance for production purposes.
@ -111,7 +111,7 @@ As a user of the ZITADEL Cloud Customer Portal, you now can create multiple inst
![Access Instance](/img/guides/quickstart/v2_7.png)
### 3. Create your First Project
### 3. Create your first project
1. To create a project in the instance you just created, click on “Create Project”.
@ -125,7 +125,7 @@ As a user of the ZITADEL Cloud Customer Portal, you now can create multiple inst
![Project Created](/img/guides/quickstart/21.png)
### 4. Add Users (optional)
### 4. Add users (optional)
[Skip optional steps](quickstart/#7-create-an-application-in-your-project) and jump directly to the create application step.
@ -145,7 +145,7 @@ As a user of the ZITADEL Cloud Customer Portal, you now can create multiple inst
![User Info](/img/guides/quickstart/29.png)
### 5. Add Roles to your Project (optional)
### 5. Add roles to your project (optional)
1. To add roles to your project, click on “Roles” on the left as shown below. Next, click on the “New” button.
@ -163,7 +163,7 @@ As a user of the ZITADEL Cloud Customer Portal, you now can create multiple inst
![Add Role](/img/guides/quickstart/25.png)
### 6. Add Authorizations to your Project
### 6. Add authorizations to your project
1. Click on “Authorizations” on the top menu.
@ -193,7 +193,7 @@ As a user of the ZITADEL Cloud Customer Portal, you now can create multiple inst
![Add Authorization](/img/guides/quickstart/37.png)
### 7. Create an Application in your Project
### 7. Create an application in your project
We will now create an application in the project, which will allow our React client application to access protected resources through the use of the OpenID Connect (OIDC) protocol.
@ -241,7 +241,7 @@ We will now create an application in the project, which will allow our React cli
![Add Application](/img/guides/quickstart/50.png)
### 8. Obtaining ClientId and OIDC Endpoints for your Application {#referred1}
### 8. Obtain ClientId and OIDC endpoints for your application {#referred1}
You will need the ClientId and the OIDC endpoints (issuer and userinfo) when building your React application. The issuer URL is the base URL for the OIDC provider and includes the path to the OIDC discovery document, which contains information about the OIDC provider, including the authorization and token endpoints. By providing the issuer URL, you can use the OIDC library to automatically determine the endpoints for these requests.
The authorization endpoint is used to initiate the authorization process, the token endpoint is used to exchange authorization codes for access tokens, and the userinfo endpoint is used to retrieve information about the user. You need an access token to access the userinfo endpoint and other protected resources.
@ -256,9 +256,9 @@ The authorization endpoint is used to initiate the authorization process, the to
And with that, configuring ZITADEL for our application is complete. Now we can move on to building our React application. Let's get coding!
## Create Your React Application with ZITADEL OIDC PKCE Authentication
## Create your React application with ZITADEL OIDC PKCE authentication
### 1. Functional Requirements of the Application
### 1. Functional requirements of the application
1. The user navigates to the React app (client) and clicks the "login" button.
2. The app initiates the authorization process by redirecting the users browser to the authorization endpoint of the ZITADEL instance, along with the PKCE parameters (code challenge, and code challenge method).
@ -298,7 +298,7 @@ To install Visual Studio Code, go to their [website](https://code.visualstudio.c
### 3. Development
#### 1. Create Project
#### 1. Create project
1. Open a new terminal window in Visual Studio Code.
2. Navigate to the folder where you want to create the React app.
3. Run the following command to create a new React app named "react-oidc-zitadel":
@ -318,7 +318,7 @@ This will create the following files in your project:
``` npm install react-router-dom oidc-client-ts ```
#### 2. Add Source Files
#### 2. Add source files
The code needed to run this project can be found [here](https://github.com/zitadel/react-user-authentication).
@ -595,7 +595,7 @@ root.render(
reportWebVitals();
```
### 4. Running the Application
### 4. Running the application
1. Run ```npm start``` to start the development server.
2. Open your browser and navigate to ```http://localhost:3000/``` to view the app.

View File

@ -1,27 +0,0 @@
---
title: Overview
---
import {ListElement, ListWrapper, ICONTYPE} from '../../src/components/list';
import Column from '../../src/components/column';
This section contains important agreements, policies and appendices relevant for users of our websites and services.
All documents will be provided in English language.
<Column>
<ListWrapper title="Main documents">
<ListElement link="/docs/legal/terms-of-service" type={ICONTYPE.POLICY} title="Terms of Service" description="" />
<ListElement link="/docs/legal/data-processing-agreement" type={ICONTYPE.POLICY} title="Data Processing Agreement" description="" />
<ListElement link="/docs/legal/privacy-policy" type={ICONTYPE.POLICY} title="Privacy Policy" description="" />
</ListWrapper>
<ListWrapper title="Service">
<ListElement link="/docs/legal/service-level-description" type={ICONTYPE.SERVICE} title="Service Level" description="Service levels offered by ZITADEL Cloud" />
<ListElement link="/docs/legal/cloud-service-description" type={ICONTYPE.SERVICE} title="Cloud Service" description="Service description and data location" />
<ListElement link="/docs/legal/terms-of-service-dedicated" type={ICONTYPE.SERVICE} title="Dedicated Instances" description="Terms and Conditions of dedicated Instances" />
</ListWrapper>
<ListWrapper title="Annexes">
<ListElement link="/docs/legal/support-services" type={ICONTYPE.POLICY} title="Support Services" description="Support services offered by ZITADEL and CAOS Ltd." />
<ListElement link="/docs/legal/acceptable-use-policy" type={ICONTYPE.POLICY} title="Acceptable Use Policy" description="Obligations while using ZITADEL Services" />
<ListElement link="/docs/legal/rate-limit-policy" type={ICONTYPE.POLICY} title="Rate Limit Policy" description="How ZITADEL will use rate limiting" />
</ListWrapper>
</Column>

View File

@ -1,39 +0,0 @@
---
title: Dedicated Instance Terms
custom_edit_url: null
---
## General
Last revised: June 3, 2022
### Background
Within the scope of the Framework Agreement, the Customer may choose to purchase a subscription that requires a dedicated instance of ZITADEL. These additional terms for dedicated instance ("**Dedicated Instance Terms**") apply in addition to the Framework Agreement.
### Service
CAOS operates and manages a **Dedicated Instance** of ZITADEL in a private infrastructure environment dedicated for the Customer and provides support services for the Customer according the Purchase Order, these terms, agreed [**Service Level Description**](service-level-description), and [**Support Service Descriptions**](support-services).
Each Dedicated Instance consists, except agreed otherwise in writing, of a multi-zonal high-availability configuration that guarantees loads up to the specified [rate limits](rate-limit-policy#what-rate-limits-do-apply).
### Operations
CAOS will install and manage the Dedicated Instance on infracstructure provided by preferred cloud providers. Costs for infrastructure or cloud providers are not included in the Subscription, if not agreed otherwise in writing.
You may choose to provide the required infrastructure yourself. You must comply with the requirements and prerequisites outlined in the purchase order.
You may not modify, maintain or attempt to modify the Dedicated Instance, except with prior instructions by CAOS.
CAOS will use the same backup strategy as for ZITADEL Cloud (public cloud) services, except otherwise agreed between you and CAOS in writing.
### Maintenance and Updates
We will access, modify, and maintain the Dedicated Instance at times solely determined by CAOS (**"Regular Maintenance"**).
Under certain subscription plans, the Customer may agree a custom frequency and times for changes and updates. CAOS will coordinate the cadence and the changes with the Customer. To guarantee the quality of service, maintenance will occur on regular basis, typically monthly or sooner for security or performance related patches (**"Emergency Maintenance"**), but no longer than on quarterly basis.
If you fail to permit CAOS to conduct Regular Maintenance for 3 consecutive months or Emergency Maintenance within 5 days of notification, then CAOS will raise this issue with the Customer via Escalation Process. In case the issue is not resolved 5 days after such an escalation, CAOS may terminate the subscription with 30 days prior written notice to Customer. CAOS is not obligated to provide the service according to the terms and SLA, nor is CAOS liable to any security breach or damages after failure to permit Regular Maintenance for 3 consecutive months, or Emergency Maintenance for 5 days after notification.
### Incidents
Incidents are handled as documented in the [**Support Service Descriptions**](support-services). If the Customer choose in Purchase Order to provide the required infrastructure, then any incidents related to the infrastructure of the Dedicated Instance have to be resolved through the Customer directly.

View File

@ -25,10 +25,6 @@ The following policies complement the TOS. When accepting the TOS, you accept th
* [**Acceptable Use Policy**](acceptable-use-policy) - What we understand as acceptable and fair use of our Services
* [**Rate Limit Policy**](rate-limit-policy) - How we avoid overloads of our services
This Agreement is extended with additional terms, in case your Subscription requires a Dedicated Instance. When you enter the Agreement with us, you accept these additional agreements.
* [**Dedicated Instance Terms**](terms-of-service-dedicated) - How we provide our services for a dedicated instance
### Alterations
Any provisions which deviate from these TOS must be agreed in writing between the Customer and us. Such agreements shall take precedence over the TOS outlined in this document.
@ -195,7 +191,7 @@ Should any provision of these TOS be or become invalid, this shall not affect th
These TOS shall enter into force as of 15.07.2022.
Last revised: June 14, 2022
Last revised: May 12, 2023
### Amendments

View File

@ -1,133 +0,0 @@
---
title: Overview
---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import { Card, CardWrapper } from "../../src/components/card";
Get started with ZITADEL quickly by reading a quickstart or by cloning a [ZITADEL example](https://github.com/search?q=topic%3Aexamples+org%3Azitadel) repo.
<Tabs>
<TabItem value="app" label="Web · Native applications" default>
<CardWrapper>
<Card
link="/docs/examples/login/angular"
imageSource="/docs/img/tech/angular.svg"
title="Angular"
description="Add the user login to your application and query some data from the userinfo endpoint"
/>
<Card
link="/docs/examples/login/react"
imageSource="/docs/img/tech/react.png"
title="React"
description="Logs into your application and queries some data from the userinfo endpoint"
/>
<Card
link="/docs/examples/login/flutter"
imageSource="/docs/img/tech/flutter.svg"
title="Flutter"
description="Mobile Application working for iOS and Android that authenticates your user."
/>
<Card
link="/docs/examples/login/nextjs"
imageSource="/docs/img/tech/nextjs.svg"
title="NextJS"
description="A simple application to log into your user account and query some data from User endpoint."
/>
<Card
link="/docs/examples/login/nextjs-b2b"
imageSource="/docs/img/tech/nextjs.svg"
title="NextJS B2B Scenario"
description="An application to showcase your user account having multiple organizations and the use of Personal Access Tokens."
/>
</CardWrapper>
</TabItem>
<TabItem value="apis" label="APIs">
<CardWrapper>
<Card
link="/docs/examples/secure-api/go"
imageSource="/docs/img/tech/golang.svg"
title="GO"
description="This example shows you how to secure an API written in GO."
/>
<Card
link="/docs/examples/secure-api/python-flask"
imageSource="/docs/img/tech/python.svg"
title="Python"
description="This example shows you how to secure a Python3 Flask API."
/>
<Card
link="/docs/examples/secure-api/dot-net"
imageSource="/docs/img/tech/dotnet.svg"
title=".NET"
description="This example shows you how to secure a .NET API."
/>
</CardWrapper>
</TabItem>
<TabItem value="zitadel" label="ZITADEL · APIs">
<CardWrapper>
<Card
link="/docs/examples/call-zitadel-api/go"
imageSource="/docs/img/tech/golang.svg"
title="GO"
description="Demonstrates how to fetch some data from the ZITADEL management API."
/>
<Card
link="/docs/examples/call-zitadel-api/dot-net"
imageSource="/docs/img/tech/dotnet.svg"
title=".NET"
description="This integration guide shows you how to integrate ZITADEL into your .NET application. It demonstrates how to fetch some data from the ZITADEL management API."
/>
</CardWrapper>
</TabItem>
<TabItem value="proxy" label="Proxy">
<CardWrapper>
<Card
link="/docs/examples/identity-proxy/oauth2-proxy"
imageSource="/docs/img/tech/oauth2-proxy.svg"
title="OAuth 2.0 Proxy"
description="Allows services to delegate the authentication flow to a IDP, for example ZITADEL"
/>
</CardWrapper>
</TabItem>
</Tabs>
## Clone a sample project
<CardWrapper>
<Card
githubLink="https://github.com/zitadel/zitadel-java"
title="Java"
label="Java"
/>
<Card
githubLink="https://github.com/zitadel/zitadel-python3"
title="Python"
label="Python"
/>
<Card
githubLink="https://github.com/zitadel/zitadel-angular"
title="Angular"
label="Web · Mobile Web"
/>
<Card
githubLink="https://github.com/zitadel/zitadel-nextjs"
title="NextJS"
label="Web · Mobile Web"
/>
<Card
githubLink="https://github.com/zitadel/zitadel_flutter"
title="Flutter"
label="Android · iOS · Web · Mobile Web"
/>
</CardWrapper>
## Libraries
| Language | Description | Link |
| -------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Go | Go client library for ZITADEL. | [https://github.com/zitadel/zitadel-go](https://github.com/zitadel/zitadel-go) |
| .Net | Authentication / Authorization library written in dotnet for the asp.net web application package. | [https://github.com/zitadel/zitadel-net](https://github.com/zitadel/zitadel-net) |
| Dart | Dart library for ZITADEL, contains gRPC and API access elements. | [https://github.com/zitadel/zitadel-dart](https://github.com/zitadel/zitadel-dart) |
| Elixir | API Client for the ZITADEL API. | [https://github.com/jshmrtn/zitadel_api](https://github.com/jshmrtn/zitadel_api) |

View File

@ -1,5 +1,6 @@
---
title: Overview
title: Deploy ZITADEL
sidebar_label: Overview
---
Choose your platform and run ZITADEL with the most minimal configuration possible.
@ -13,7 +14,8 @@ Choose your platform and run ZITADEL with the most minimal configuration possibl
## Prerequisites
- For test environments, ZITADEL does not need many resources, 1 CPU and 512MB memory are more than enough. (With more CPU, the password hashing might be faster)
- A cockroachDB or Postgresql (currently in beta) as only needed storage
- A CockroachDB or Postgresql as only needed storage. Make sure to read our [Production Guide](./self-hosting/manage/production#prefer-cockroachdb) before you decide to use Postgresql.
)
## Releases

View File

@ -1,10 +1,16 @@
## Postgres
:::caution
Postgres extension is currently in beta.
PostgreSQL extension is currently in [Beta](/docs/support/software-release-cycles-support#beta).
Beta state will be removed as soon as automated tests are implemented. [Github Issue](https://github.com/zitadel/zitadel/issues/5741)
:::
:::caution
Be aware that PostgreSQL is only [Enterprise Supported](/docs/support/software-release-cycles-support#partially-supported).
:::
If you want to use a PostgreSQL database instead of CockroachDB you can [overwrite the default configuration](../configure/configure.mdx).
Make sure to read our [Production Guide](./self-hosting/manage/production#prefer-cockroachdb) before you decide to use it.
Currently versions >= 14 are supported.

View File

@ -71,6 +71,11 @@ as horizontal scaling is much easier than with PostgreSQL.
Also, if you are concerned about multi-regional data locality,
[the way to go is with CockroachDB](https://www.cockroachlabs.com/docs/stable/multiregion-overview.html).
The indexes for the database are optimized using load tests from [ZITADEL Cloud](https://zitadel.com),
which runs with CockroachDB.
If you identify problems with your Postgresql during load tests that indicate that the indexes are not optimized,
please create an issue in our [github repository](https://github.com/zitadel/zitadel).
### Configure ZITADEL
Depending on your environment, you maybe would want to tweak some settings about how ZITADEL interacts with the database in the database section of your ZITADEL configuration. Read more about your [database configuration options](/docs/self-hosting/manage/database).

View File

@ -6,7 +6,7 @@ Quotas is an enterprise feature that is relevant if you want to host ZITADEL as
It enables you to limit usage and/or register webhooks that trigger on configurable usage levels for certain units.
For example, you might want to report usage to an external billing tool and notify users when 80 percent of a quota is exhausted.
Quotas are currently supported [for the instance level only](/concepts/structure/instance).
Please refer to the [system API docs](/apis/system) for detailed explanations about how to use the quotas feature.
Please refer to the [system API docs](/apis/resources/system) for detailed explanations about how to use the quotas feature.
ZITADEL supports limiting authenticated requests and action run seconds

View File

@ -0,0 +1,72 @@
---
title: Support States & Software Release Cycle
---
## Support States
It's important to note that support may differ depending on the feature, and not all features may be fully supported.
We always strive to provide the best support possible for our customers and community,
but we may not be able to provide immediate or comprehensive support for all features.
Also the support may differ depending on your contracts. Read more about it on our [Legal page](/docs/legal)
### Supported
Supported features are those that are guaranteed to work as intended and are fully tested by our team.
If you encounter any issues with a supported feature, please contact us by creating a [bug report](https://github.com/zitadel/zitadel/issues/new/choose).
We will review the issues according to our [product management process](https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md#product-management).
In case you are eligible to [support services](/docs/legal/support-services) get in touch via one of our support channels and we will provide prompt response to the issues you may experience and make our best effort to assist you to find a resolution.
:::info Security Issues
Please report any security issues immediately to the indicated address in our [security.txt](https://zitadel.com/.well-known/security.txt)
:::
### Enterprise Supported
Enterprise supported features are those where we provide support only to users eligible for enterprise [support services](/docs/legal/support-services).
These features should be functional for eligible users, but may have some limitations for a broader use.
If you encounter issues with an enterprise supported feature and you are eligible for enterprise support services, we will provide a prompt response to the issues you may experience and make our best effort to assist you to find a resolution.
**Enterprise supported features**
- Database PostgreSQL
- LDAP Identity Provider
- [Terraform Provider](https://github.com/zitadel/terraform-provider-zitadel)
### Community Supported
Community supported features are those that have been developed by our community and may not have undergone extensive testing or support from our team.
If you encounter issues with a community supported feature, we encourage you to seek help from our community or other online resources, where other users can provide assistance:
- Join our [Discord Chat](https://zitadel.com/chat)
- Search [Github Issues](https://github.com/search?q=org%3Azitadel+&type=issues) and report a new issue
- Search [Github Discussions](https://github.com/search?q=org%3Azitadel+&type=discussions) and open a new discussion as question or idea
## Software Release Cycle
It's important to note that both Alpha and Beta software can have breaking changes, meaning they are not backward-compatible with previous versions of the software.
Therefore, it's recommended to use caution when using Alpha and Beta software, and to always back up important data before installing or testing new software versions.
Only features in General Availability will be covered by support services.
We encourage our community to test Alpha and Beta software and provide feedback via our [Discord Chat](https://zitadel.com/chat).
### Alpha
The Alpha state is our initial testing phase.
It is available to everyone, but it is not yet complete and may contain bugs and incomplete features.
We recommend that users exercise caution when using Alpha software and avoid using it for critical tasks, as support is limited during this phase.
### Beta
The Beta state comes after the Alpha phase and is a more stable version of the software.
It is feature-complete, but may still contain bugs that need to be fixed before general availability.
While it is available to everyone, we recommend that users exercise caution when using Beta software and avoid using it for critical tasks.
During this phase, support is limited as we focus on testing and bug fixing.
### General Available
Generally available features are available to everyone and have the appropriate test coverage to be used for critical tasks.
The software will be backwards-compatible with previous versions, for exceptions we will publish a [technical advisory](https://zitadel.com/docs/support/technical_advisory).
Features in General Availability are not marked explicitly.

View File

@ -1,5 +1,6 @@
---
title: Introduction
title: Trainings
sidebar_label: Introduction
---
The following pages describe the the trainings provided by ZITADEL. These trainings are intended for onboarding and during the course of a Support Program.

View File

@ -8,8 +8,7 @@ You will find some possible error messages here, what the problem is and what so
Join or [Chat](https://zitadel.com/chat) or open a [Discussion](https://github.com/zitadel/zitadel/discussions).
:::
## User Agent does not correspond
## User agent does not correspond
This error appeared for some users as soon as they were redirected to the login page of ZITADEL.
ZITADEL uses some cookies to identify the browser/user agent of the user, so it is able to store the active user sessions. By blocking the cookies the functions of ZITADEL will be affected.
@ -34,6 +33,14 @@ Do you still face this issue? Please contact us, and we will help you find out w
`ID=QUERY-n0wng Message=Instance not found`
If you're in an self-hosting scenario with a custom domain, you need to instruct ZITADEL to use the `ExternalDomain`.
You can find more instruction in our guide about [custom domains](https://zitadel.com/docs/self-hosting/manage/custom-domain).
If you're self hosting with a custom domain, you need to instruct ZITADEL to use the `ExternalDomain`.
You can find further instructions in our guide about [custom domains](https://zitadel.com/docs/self-hosting/manage/custom-domain).
We also provide a guide on how to [configure](https://zitadel.com/docs/self-hosting/manage/configure) ZITADEL with variables from files or environment variables.
## WebFinger requirement for Tailscale
The WebFinger requirement and setup is a step a user has to take outside of their IdP set-up. WebFinger is a protocol which supports the ability for OIDC issuer discovery, and we use it to prove that the user has administrative control over the domain and to retrieve the issuer. This is a requirement we have in place for all users, regardless of their IdP, who use custom OIDC with Tailscale.
On their custom domain, e.g example.com, users need to host a WebFinger endpoint at https://example.com/.well-known/webfinger. When queried, this endpoint returns a JSON response detailing the issuer. Users would need to host the endpoint with the link to the ZITADEL issuer. Tailscale only looks up this endpoint once when a user signs up, and will only look up this endpoint again if the user needs to make a configuration change to their identity provider.
The requirements and a set up guide is detailed in the [Tailscale documentation](https://tailscale.com/kb/1240/sso-custom-oidc/).

View File

@ -83,7 +83,7 @@ module.exports = {
},
{
type: "doc",
docId: "legal/introduction",
docId: "legal",
label: "Legal",
position: "right",
},
@ -234,49 +234,49 @@ module.exports = {
config: {
auth: {
specPath: ".artifacts/openapi/zitadel/auth.swagger.json",
outputDir: "docs/apis/auth",
outputDir: "docs/apis/resources/auth",
sidebarOptions: {
groupPathsBy: "tag",
},
},
mgmt: {
specPath: ".artifacts/openapi/zitadel/management.swagger.json",
outputDir: "docs/apis/mgmt",
outputDir: "docs/apis/resources/mgmt",
sidebarOptions: {
groupPathsBy: "tag",
},
},
admin: {
specPath: ".artifacts/openapi/zitadel/admin.swagger.json",
outputDir: "docs/apis/admin",
outputDir: "docs/apis/resources/admin",
sidebarOptions: {
groupPathsBy: "tag",
},
},
system: {
specPath: ".artifacts/openapi/zitadel/system.swagger.json",
outputDir: "docs/apis/system",
outputDir: "docs/apis/resources/system",
sidebarOptions: {
groupPathsBy: "tag",
},
},
user: {
specPath: ".artifacts/openapi/zitadel/user/v2alpha/user_service.swagger.json",
outputDir: "docs/apis/user_service",
outputDir: "docs/apis/resources/user_service",
sidebarOptions: {
groupPathsBy: "tag",
},
},
session: {
specPath: ".artifacts/openapi/zitadel/session/v2alpha/session_service.swagger.json",
outputDir: "docs/apis/session_service",
outputDir: "docs/apis/resources/session_service",
sidebarOptions: {
groupPathsBy: "tag",
},
},
settings: {
specPath: ".artifacts/openapi/zitadel/settings/v2alpha/settings_service.swagger.json",
outputDir: "docs/apis/settings_service",
outputDir: "docs/apis/resources/settings_service",
sidebarOptions: {
groupPathsBy: "tag",
},

View File

@ -15,7 +15,7 @@ http {
}
location /docs {
root /usr/share/nginx/html;
alias /usr/share/nginx/html;
index /docs/index.html;
try_files $uri $uri/ /docs/index.html?q=$query_string;
}

View File

@ -33,7 +33,7 @@ module.exports = {
"examples/sdks",
{
type: "category",
label: "Example Applications",
label: "Example applications",
items: [
"examples/introduction",
{
@ -57,8 +57,14 @@ module.exports = {
{
type: "category",
label: "Cloud",
link: {
type: "generated-index",
title: "Overview",
slug: "guides/manage/cloud/overview",
description:
"Our customer portal is used to manage all your ZITADEL instances. You can also manage your subscriptions, billing, newsletters and support requests.",
},
items: [
"guides/manage/cloud/overview",
"guides/manage/cloud/start",
"guides/manage/cloud/instances",
"guides/manage/cloud/billing",
@ -136,7 +142,7 @@ module.exports = {
items: [
{
type: "category",
label: "Authenticate Users",
label: "Authenticate users",
collapsed: true,
items: [
"guides/integrate/login-users",
@ -146,7 +152,7 @@ module.exports = {
},
{
type: "category",
label: "Configure Identity Providers",
label: "Configure identity providers",
link: {
type: "generated-index",
title: "Let users login with their preferred identity provider",
@ -174,7 +180,7 @@ module.exports = {
items: [
{
type: "category",
label: "Authenticate Service Users",
label: "Authenticate service users",
link: {
type: "generated-index",
title: "Authenticate Service Users",
@ -194,7 +200,7 @@ module.exports = {
"guides/integrate/event-api",
{
type: "category",
label: "Example Code",
label: "Example code",
items: [
"examples/call-zitadel-api/go",
"examples/call-zitadel-api/dot-net",
@ -247,13 +253,13 @@ module.exports = {
},
{
type: "category",
label: "Solution Scenarios",
label: "Solution scenarios",
link: {
type: "generated-index",
title: "Solution Scenarios",
title: "Solution scenarios",
slug: "guides/solution-scenarios/introduction",
description:
"Customers of an SaaS Identity and Access Management System usually have all distinct use cases and requirements. This guide attempts to explain real-world implementations and break them down into Solution Scenarios which aim to help you getting started with ZITADEL.",
"Customers of an SaaS Identity and access management system usually have all distinct use cases and requirements. This guide attempts to explain real-world implementations and break them down into solution scenarios which aim to help you getting started with ZITADEL.",
},
collapsed: true,
items: [
@ -268,8 +274,14 @@ module.exports = {
type: "category",
label: "Concepts",
collapsed: true,
link: {
type: "generated-index",
title: "Concepts and Features",
slug: "concepts",
description:
"This part of our documentation contains ZITADEL specific or general concepts required to understand the system or our guides.",
},
items: [
"concepts/introduction",
"concepts/structure/instance",
"concepts/structure/organizations",
"concepts/structure/projects",
@ -310,10 +322,11 @@ module.exports = {
label: "Support",
collapsed: true,
items: [
"support/software-release-cycles-support",
"support/troubleshooting",
{
type: 'category',
label: "Technical Advisory",
label: "Technical advisory",
link: {
type: 'doc',
id: 'support/technical_advisory',
@ -349,96 +362,96 @@ module.exports = {
items: [
{
type: "category",
label: "Authenticated User",
label: "Authenticated user",
link: {
type: "generated-index",
title: "Auth API",
slug: "/apis/auth",
slug: "/apis/resources/auth",
description:
"The authentication API (aka Auth API) is used for all operations on the currently logged in user. The user id is taken from the sub claim in the token.",
},
items: require("./docs/apis/auth/sidebar.js"),
items: require("./docs/apis/resources/auth/sidebar.js"),
},
{
type: "category",
label: "Organization Objects",
label: "Organization objects",
link: {
type: "generated-index",
title: "Management API",
slug: "/apis/mgmt",
slug: "/apis/resources/mgmt",
description:
"The management API is as the name states the interface where systems can mutate IAM objects like, organizations, projects, clients, users and so on if they have the necessary access rights. To identify the current organization you can send a header x-zitadel-orgid or if no header is set, the organization of the authenticated user is set.",
},
items: require("./docs/apis/mgmt/sidebar.js"),
items: require("./docs/apis/resources/mgmt/sidebar.js"),
},
{
type: "category",
label: "Instance Objects",
label: "Instance objects",
link: {
type: "generated-index",
title: "Admin API",
slug: "/apis/admin",
slug: "/apis/resources/admin",
description:
"This API is intended to configure and manage one ZITADEL instance itself.",
},
items: require("./docs/apis/admin/sidebar.js"),
items: require("./docs/apis/resources/admin/sidebar.js"),
},
{
type: "category",
label: "Instance Lifecycle",
label: "Instance lifecycle",
link: {
type: "generated-index",
title: "System API",
slug: "/apis/system",
slug: "/apis/resources/system",
description:
"This API is intended to manage the different ZITADEL instances within the system.\n" +
"\n" +
"Checkout the guide how to access the ZITADEL System API.",
},
items: require("./docs/apis/system/sidebar.js"),
items: require("./docs/apis/resources/system/sidebar.js"),
},
{
type: "category",
label: "User Lifecycle (Alpha)",
label: "User lifecycle (alpha)",
link: {
type: "generated-index",
title: "User Service API (Alpha)",
slug: "/apis/user_service",
title: "User service API (Alpha)",
slug: "/apis/resources/user_service",
description:
"This API is intended to manage users in a ZITADEL instance.\n"+
"\n"+
"This project is in alpha state. It can AND will continue breaking until the services provide the same functionality as the current login.",
},
items: require("./docs/apis/user_service/sidebar.js"),
items: require("./docs/apis/resources/user_service/sidebar.js"),
},
{
type: "category",
label: "Session Lifecycle (Alpha)",
label: "Session lifecycle (Alpha)",
link: {
type: "generated-index",
title: "Session Service API (Alpha)",
slug: "/apis/session_service",
title: "Session service API (Alpha)",
slug: "/apis/resources/session_service",
description:
"This API is intended to manage sessions in a ZITADEL instance.\n"+
"\n"+
"This project is in alpha state. It can AND will continue breaking until the services provide the same functionality as the current login.",
},
items: require("./docs/apis/session_service/sidebar.js"),
items: require("./docs/apis/resources/session_service/sidebar.js"),
},
{
type: "category",
label: "Settings Lifecycle (Alpha)",
label: "Settings lifecycle (alpha)",
link: {
type: "generated-index",
title: "Settings Service API (Alpha)",
slug: "/apis/settings_service",
title: "Settings service API (Alpha)",
slug: "/apis/resources/settings_service",
description:
"This API is intended to manage settings in a ZITADEL instance.\n"+
"\n"+
"This project is in alpha state. It can AND will continue breaking until the services provide the same functionality as the current login.",
"This project is in alpha state. It can AND will continue to break until the services provide the same functionality as the current login.",
},
items: require("./docs/apis/settings_service/sidebar.js"),
items: require("./docs/apis/resources/settings_service/sidebar.js"),
},
{
type: "category",
@ -489,7 +502,7 @@ module.exports = {
},
{
type: "doc",
label: "gRPC Status Codes",
label: "gRPC status codes",
id: "apis/statuscodes"
},
{
@ -500,7 +513,7 @@ module.exports = {
},
{
type: 'link',
label: 'Rate Limits (Cloud)', // The link label
label: 'Rate limits (cloud)', // The link label
href: '/legal/rate-limit-policy', // The internal path
},
],
@ -537,15 +550,24 @@ module.exports = {
],
},
],
support: [
],
legal: [
"legal/introduction",
{
type: "category",
label: "Legal agreements",
collapsed: false,
link: {
type: "generated-index",
title: "Legal agreements",
slug: "legal",
description:
"This section contains important agreements, policies and appendices relevant for users of our websites and services. All documents will be provided in English language.",
},
items: [
"legal/terms-of-service",
"legal/data-processing-agreement",
{
type: "category",
label: "Service Description",
label: "Service description",
collapsed: false,
items: [
"legal/cloud-service-description",
@ -555,11 +577,10 @@ module.exports = {
},
{
type: "category",
label: "Additional terms",
label: "Support program",
collapsed: true,
items: [
"legal/terms-support-service",
"legal/terms-of-service-dedicated",
],
},
{
@ -573,5 +594,7 @@ module.exports = {
"legal/vulnerability-disclosure-policy",
],
},
]
},
],
};

View File

@ -154,19 +154,19 @@ const features = [
<div className={styles.apilinks}>
<ListWrapper>
<ListElement
link="/docs/apis/auth/authentication-api-aka-auth"
link="/docs/apis/resources/auth/authentication-api-aka-auth"
type={ICONTYPE.APIS}
title="Authenticated User"
description="All operations on the currently authenticated user."
/>
<ListElement
link="/docs/apis/mgmt/management-api"
link="/docs/apis/resources/mgmt/management-api"
type={ICONTYPE.APIS}
title="Organization Objects"
description="Mutate IAM objects like organizations, projects, clients, users etc."
/>
<ListElement
link="/docs/apis/admin/administration-api-aka-admin"
link="/docs/apis/resources/admin/administration-api-aka-admin"
type={ICONTYPE.APIS}
title="Instance Objects"
description="Configure and manage the IAM instance."

View File

@ -1,5 +1,5 @@
Log:
Level: debug
Level: info
ExternalDomain: host.docker.internal
ExternalSecure: false
@ -33,7 +33,10 @@ LogStore:
Quotas:
Access:
ExhaustedCookieKey: "zitadel.quota.limiting"
ExhaustedCookieMaxAge: "60s"
ExhaustedCookieMaxAge: "600s"
Console:
InstanceManagementURL: "https://example.com/instances/{{.InstanceID}}"
Projections:
Customizations:

View File

@ -1,5 +1,5 @@
Log:
Level: debug
Level: info
ExternalDomain: localhost
ExternalSecure: false
@ -33,7 +33,10 @@ LogStore:
Quotas:
Access:
ExhaustedCookieKey: "zitadel.quota.limiting"
ExhaustedCookieMaxAge: "60s"
ExhaustedCookieMaxAge: "600s"
Console:
InstanceManagementURL: "https://example.com/instances/{{.InstanceID}}"
Projections:
Customizations:

View File

@ -94,7 +94,7 @@ describe('quotas', () => {
});
});
it('authenticated requests are limited', () => {
it('only authenticated requests are limited', () => {
cy.get<Array<string>>('@authenticatedUrls').then((urls) => {
cy.get<Context>('@ctx').then((ctx) => {
const start = new Date();
@ -109,9 +109,9 @@ describe('quotas', () => {
});
expectCookieDoesntExist();
const expiresMax = new Date();
expiresMax.setMinutes(expiresMax.getMinutes() + 2);
expiresMax.setMinutes(expiresMax.getMinutes() + 20);
cy.request({
url: urls[0],
url: urls[1],
method: 'GET',
auth: {
bearer: ctx.api.token,
@ -129,7 +129,19 @@ describe('quotas', () => {
createHumanUser(ctx.api, testUserName, false).then((res) => {
expect(res.status).to.equal(429);
});
// visit limited console
cy.visit('/users/me');
cy.contains('#authenticated-requests-exhausted-dialog button', 'Continue').click();
const upgradeInstancePage = `https://example.com/instances/${ctx.instanceId}`;
cy.origin(upgradeInstancePage, { args: { upgradeInstancePage } }, ({ upgradeInstancePage }) => {
cy.location('href').should('equal', upgradeInstancePage);
});
// upgrade instance
ensureQuotaIsRemoved(ctx, Unit.AuthenticatedRequests);
// visit upgraded console again
cy.visit('/users/me');
cy.get('[data-e2e="top-view-title"]');
expectCookieDoesntExist();
createHumanUser(ctx.api, testUserName);
expectCookieDoesntExist();
});

View File

@ -8,6 +8,8 @@
"e2e:golang": "npm run e2e --",
"open:golangangular": "CYPRESS_BASE_URL=http://localhost:4200 CYPRESS_BACKEND_URL=http://localhost:8080 npm run open --",
"e2e:golangangular": "CYPRESS_BASE_URL=http://localhost:4200 CYPRESS_BACKEND_URL=http://localhost:8080 npm run e2e --",
"open:angulargolang": "npm run open:golangangular --",
"e2e:angulargolang": "npm run e2e:golangangular --",
"open:angular": "CYPRESS_BASE_URL=http://localhost:4200 CYPRESS_BACKEND_URL=http://localhost:8080 CYPRESS_WEBHOOK_HANDLER_HOST=host.docker.internal npm run open --",
"e2e:angular": "CYPRESS_BASE_URL=http://localhost:4200 CYPRESS_BACKEND_URL=http://localhost:8080 CYPRESS_WEBHOOK_HANDLER_HOST=host.docker.internal npm run e2e --",
"lint": "prettier --check cypress",

Some files were not shown because too many files have changed in this diff Show More