mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-20 06:24:25 +00:00
## Todos for release - [x] Configure Env in docs project on vercel - [x] Configure Root Path in the docs project on vercel - [ ] Remove old CSP https://github.com/zitadel/website/pull/1592 ## What we did This pull request migrates the project documentation from the old `docs/` directory to the new `apps/docs/` directory, introduces a new documentation system built with Next.js and Fumadocs, and updates all relevant references, configuration files, and documentation to reflect this change. It also adds new configuration and ignore files for the new documentation app, updates CI and linting to exclude the new docs from certain checks, and revises the contributing guidelines accordingly. **Documentation System Migration and New Docs App** * Migrated all documentation from `docs/` to `apps/docs/`, and updated all references in `README.md`, `CONTRIBUTING.md`, and other files to point to the new location. [[1]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L585-L640) [[2]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L660-R607) [[3]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L740-R687) [[4]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L2-R3) [[5]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L30-R30) * Added a new Next.js/Fumadocs-based documentation app under `apps/docs/`, including core app files, layouts, routing, search API, and a comprehensive `README.md` with development and contribution instructions. [[1]](diffhunk://#diff-5a1b07344a2c1b4d3f37b23ff1388b62cd9f57dea3c1cd23d8a0412b7602b132R1-R74) [[2]](diffhunk://#diff-462b9ad1eabbb7d1c29bb9c36e4931eb180fd7190900e6d2babf8f4d66ad1c28R1-R39) [[3]](diffhunk://#diff-e16ae25660ded787b10ac35dea96d5ecaacf895dae0afc8a9bd4382dc79a8c87R1-R7) [apps/docs/app/[[...slug]]/layout.tsxR1-R81](diffhunk://#diff-59e08acde4e805b7aeccef1dcf98f1d71dfc550777e6b9402085cee0e9fa4e0aR1-R81), [apps/docs/app/[[...slug]]/page.tsxR1-R79](diffhunk://#diff-e5df3f80d0fa01e12d63d81f29c57a9d14e846c78fd3beabb2ef768e38fd9580R1-R79), [[4]](diffhunk://#diff-389b34918e040cacaa87cd7201ffa462cc2b0b716736f537e3d3c660ac69353bR1-R7) [[5]](diffhunk://#diff-d3b03416d1c457b19f1c27b26f2db741412df841b875c26ccadc36e4522247f4R1-R29) [[6]](diffhunk://#diff-c8fb8339570a5305809be7c618e14705fd86390dc278e6ce8ba224a7bc8b0c3cR1-R25) **Configuration and Tooling Updates** * Updated `.github/workflows/codeql.yml`, `.golangci.yaml`, and `.github/dependabot.yml` to properly handle the new docs app: excluded `apps/docs` from certain checks, added npm dependency updates for the docs app, and excluded generated content. [[1]](diffhunk://#diff-12783128521e452af0cfac94b99b8d250413c516ec71fe6d97dbea666ff7ba27L8-R14) [[2]](diffhunk://#diff-9917ddc9f1c3304218f7269265b746d997c5c0615478177b5fceecd33ef47cb5R5-R6) [[3]](diffhunk://#diff-9917ddc9f1c3304218f7269265b746d997c5c0615478177b5fceecd33ef47cb5R126-R129) [[4]](diffhunk://#diff-dd4fbda47e51f1e35defb9275a9cd9c212ecde0b870cba89ddaaae65c5f3cd28R89-R106) * Updated `.devcontainer/devcontainer.json` to use the latest Go 1.25.3 version for consistency. **Licensing and Miscellaneous** * Added `apps/docs/` to the list of licensed directories in `LICENSING.md`. These changes ensure the documentation is now maintained in a modern, scalable system and all project tooling is updated to support the new structure. --------- Co-authored-by: Federico Coppede <[email protected]>
254 lines
8.3 KiB
Plaintext
254 lines
8.3 KiB
Plaintext
---
|
|
title: Migrate Users
|
|
sidebar_label: Users
|
|
---
|
|
|
|
Migrating users from an existing system, while minimizing impact on said users, can be a challenging task.
|
|
|
|
## Individual Users
|
|
|
|
Creating individual users can be done with this endpoint: [ImportHumanUser](/reference/api/management/zitadel.management.v1.ManagementService.ImportHumanUser).
|
|
Please also consult our [guide](/guides/manage/user/reg-create-user) on how to create users.
|
|
|
|
```json
|
|
{
|
|
"userName": "test9@test9",
|
|
"profile": {
|
|
"firstName": "Road",
|
|
"lastName": "Runner",
|
|
"displayName": "Road Runner",
|
|
"preferredLanguage": "en"
|
|
},
|
|
"email": {
|
|
"email": "[email protected]",
|
|
"isEmailVerified": false
|
|
},
|
|
"hashedPassword": {
|
|
"value": "$2a$14$aPbwhMVJSVrRRW2NoM/5.esSJO6o/EIGzGxWiM5SAEZlGqCsr9DAK",
|
|
"algorithm": "bcrypt"
|
|
},
|
|
"passwordChangeRequired": false,
|
|
"otpCode": "testotp",
|
|
"requestPasswordlessRegistration": false,
|
|
"idps": [
|
|
{
|
|
"configId": "124425861423228496",
|
|
"externalUserId": "[email protected]",
|
|
"displayName": "name"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Bulk import
|
|
|
|
For bulk import use the [import endpoint](/reference/api/admin/zitadel.admin.v1.AdminService.ImportData) on the admin API:
|
|
|
|
```json
|
|
{
|
|
"timeout": "10m",
|
|
"data_orgs": {
|
|
"orgs": [
|
|
{
|
|
"orgId": "104133391254874632",
|
|
"org": {
|
|
"name": "ACME"
|
|
},
|
|
"humanUsers": [
|
|
{
|
|
"userId": "104133391271651848",
|
|
"user": {
|
|
"userName": "test9@test9",
|
|
"profile": {
|
|
"firstName": "Road",
|
|
"lastName": "Runner",
|
|
"displayName": "Road Runner",
|
|
"preferredLanguage": "de"
|
|
},
|
|
"email": {
|
|
"email": "[email protected]",
|
|
"isEmailVerified": true
|
|
},
|
|
"hashedPassword": {
|
|
"value": "$2a$14$aPbwhMVJSVrRRW2NoM/5.esSJO6o/EIGzGxWiM5SAEZlGqCsr9DAK",
|
|
"algorithm": "bcrypt"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"userId": "120080115081209416",
|
|
"user": {
|
|
"userName": "testuser",
|
|
"profile": {
|
|
"firstName": "Test",
|
|
"lastName": "User",
|
|
"displayName": "Test User",
|
|
"preferredLanguage": "und"
|
|
},
|
|
"email": {
|
|
"email": "[email protected]",
|
|
"isEmailVerified": true
|
|
},
|
|
"hashedPassword": {
|
|
"value": "$2a$14$785Fcdbpo9rn5L7E21nIAOJvGCPgWFrZhIAIfDonYXzWuZIKRAQkO",
|
|
"algorithm": "bcrypt"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"userId": "145195347319252359",
|
|
"user": {
|
|
"userName": "wile@test9",
|
|
"profile": {
|
|
"firstName": "Wile E.",
|
|
"lastName": "Coyote",
|
|
"displayName": "Wile E. Coyote",
|
|
"preferredLanguage": "en"
|
|
},
|
|
"email": {
|
|
"email": "[email protected]"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
<Callout>
|
|
We will improve the bulk import interface for users in the future.
|
|
You can show your interest or join the discussion on [this issue](https://github.com/zitadel/zitadel/issues/5524).
|
|
</Callout>
|
|
|
|
## Migrate secrets
|
|
|
|
Besides user data you need to migrate secrets, such as password hashes, OTP seeds, and public keys for passkeys (FIDO2).
|
|
The snippets in the sections below are parts from the bulk import endpoint, to clarify how the different objects can be imported.
|
|
|
|
### Passwords
|
|
|
|
ZITADEL stores passwords only as irreversible hashes, never in clear text.
|
|
Existing password hashes can be imported if they use a supported [hash algorithm](/concepts/architecture/secrets#hashed-secrets).
|
|
|
|
Import password hashes using the import API (snippet from [bulk-import](#bulk-import)):
|
|
```json
|
|
{
|
|
"userName": "test9@test9",
|
|
...,
|
|
"hashedPassword": {
|
|
"value": "$2a$14$aPbwhMVJSVrRRW2NoM/5.esSJO6o/EIGzGxWiM5SAEZlGqCsr9DAK",
|
|
"algorithm": "bcrypt"
|
|
},
|
|
"passwordChangeRequired": false,
|
|
...,
|
|
}
|
|
```
|
|
|
|
Upon initial login, ZITADEL validates the imported password using the appropriate verifier.
|
|
|
|
<Callout title="Verifiers">
|
|
In ZITADEL, a password verifier checks the validity of a password hash created with an algorithm different from the currently configured one.
|
|
It acts as a translator, allowing ZITADEL to understand and validate hashes made with older algorithms like MD5 even when the system has transitioned to newer ones like Argon2.
|
|
This is crucial during migrations or when importing user data.
|
|
Essentially, a verifier ensures ZITADEL can work with passwords hashed using various algorithms, maintaining security while transitioning to stronger hashing methods.
|
|
</Callout>
|
|
|
|
Regardless of the `passwordChangeRequired` setting, the password is rehashed using the configured hasher algorithm and stored.
|
|
This ensures consistency and allows for automatic updates even when hasher configurations are changed, such as increasing salt cost for bcrypt.
|
|
|
|
To configure the default hasher for new user passwords, set the `Algorithm` of the `PasswordHasher` in the [runtime configuration file](/self-hosting/manage/configure/configure#runtime-configuration-file)
|
|
or by the environment variable `ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_ALGORITHM`, for example:
|
|
|
|
```
|
|
ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_HASHER_ALGORITHM='pbkdf2'
|
|
```
|
|
|
|
Hasher configuration updates will automatically rehash existing passwords when they are validated or changed.
|
|
|
|
In case the hashes can't be transferred directly, you always have the option to create a user in ZITADEL without password and prompt users to create a new password.
|
|
|
|
If your legacy system receives the passwords in clear text (eg, login form) you could also directly create users via ZITADEL API.
|
|
We will explain this pattern in more detail in this guide.
|
|
|
|
### One-time passwords (OTP)
|
|
|
|
You can pass the OTP secret when creating users:
|
|
|
|
_snippet from [bulk-import](#bulk-import) example:_
|
|
```json
|
|
{
|
|
"userName": "test9@test9",
|
|
...,
|
|
"otpCode": "testotp",
|
|
...,
|
|
}
|
|
```
|
|
|
|
### Passkeys
|
|
|
|
When creating new users, you can trigger a workflow that prompts the users to setup a passkey authenticator.
|
|
|
|
_snippet from [bulk-import](#bulk-import) example:_
|
|
```json
|
|
{
|
|
"userName": "test9@test9",
|
|
...,
|
|
"requestPasswordlessRegistration": false,
|
|
...,
|
|
}
|
|
```
|
|
|
|
For passkeys to work on the new system you need to make sure that the new auth server has the same domain as the legacy auth server.
|
|
|
|
<Callout>
|
|
Currently it is not possible to migrate passkeys directly from another system.
|
|
</Callout>
|
|
|
|
## Users linked to an external IDP
|
|
|
|
A users `sub` is bound to the external [IDP's Client ID](/guides/manage/console/default-settings#identity-providers).
|
|
This means that the IDP Client ID configured in ZITADEL must be the same ID as in the legacy system.
|
|
|
|
Users should be imported with their `externalUserId`.
|
|
|
|
_snippet from [bulk-import](#bulk-import) example:_
|
|
```json
|
|
{
|
|
"userName": "test9@test9",
|
|
...,
|
|
"idps": [
|
|
{
|
|
"configId": "124425861423228496",
|
|
"externalUserId": "[email protected]",
|
|
"displayName": "name"
|
|
}
|
|
...,
|
|
}
|
|
```
|
|
|
|
You can use an Action with [post-creation flow](/apis/actions/external-authentication#post-creation) to pull information such as roles from the old system and apply them to the user in ZITADEL.
|
|
|
|
## Metadata
|
|
|
|
You can store arbitrary key-value information on a user (or Organization) in ZITADEL.
|
|
Use metadata to store additional attributes of the users, such as organizational unit, backend-id, etc.
|
|
|
|
<Callout>
|
|
Metadata must be added to users after the users were created. Currently metadata can't be added during user creation.
|
|
[API reference: User Metadata](/reference/api/user)
|
|
</Callout>
|
|
|
|
Request metadata from the userinfo endpoint by passing the required [reserved scope](/apis/openidoauth/scopes#reserved-scopes) in your auth request.
|
|
With the [complement token flow](/apis/actions/complement-token), you can also transform metadata (or roles) to custom claims.
|
|
|
|
## Authorizations / Roles
|
|
|
|
You can assign roles from owned or granted projects to a user.
|
|
|
|
<Callout>
|
|
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](/reference/api/authorization)
|
|
</Callout>
|