update main

This commit is contained in:
Elio Bischof
2025-07-25 15:54:22 +02:00
22 changed files with 241 additions and 470 deletions

View File

@@ -31,7 +31,6 @@ jobs:
uses: ./.github/workflows/console.yml
with:
node_version: "20"
buf_version: "latest"
docs:
uses: ./.github/workflows/docs.yml

View File

@@ -6,9 +6,6 @@ on:
node_version:
required: true
type: string
buf_version:
required: true
type: string
outputs:
cache_key:
value: ${{ jobs.build.outputs.cache_key }}
@@ -35,11 +32,6 @@ jobs:
restore-keys: |
console-
path: ${{ env.cache_path }}
- if: ${{ steps.cache.outputs.cache-hit != 'true' }}
uses: bufbuild/buf-setup-action@v1
with:
github_token: ${{ github.token }}
version: ${{ inputs.buf_version }}
- if: ${{ steps.cache.outputs.cache-hit != 'true' }}
uses: pnpm/action-setup@v4
- if: ${{ steps.cache.outputs.cache-hit != 'true' }}

View File

@@ -1,394 +0,0 @@
# ZITADEL Login UI
This is going to be our next UI for the hosted login. It's based on Next.js 13 and its introduced `app/` directory.
## Flow Diagram
This diagram shows the available pages and flows.
> Note that back navigation or retries are not displayed.
```mermaid
flowchart TD
A[Start] --> register
A[Start] --> accounts
A[Start] --> loginname
loginname -- signInWithIDP --> idp-success
loginname -- signInWithIDP --> idp-failure
idp-success --> B[signedin]
loginname --> password
loginname -- hasPasskey --> passkey
loginname -- allowRegister --> register
passkey-add --passwordAllowed --> password
passkey -- hasPassword --> password
passkey --> B[signedin]
password -- hasMFA --> mfa
password -- allowPasskeys --> passkey-add
password -- reset --> password-set
email -- reset --> password-set
password-set --> B[signedin]
password-change --> B[signedin]
password -- userstate=initial --> password-change
mfa --> otp
otp --> B[signedin]
mfa--> u2f
u2f -->B[signedin]
register -- password/passkey --> B[signedin]
password --> B[signedin]
password-- forceMFA -->mfaset
mfaset --> u2fset
mfaset --> otpset
u2fset --> B[signedin]
otpset --> B[signedin]
accounts--> loginname
password -- not verified yet -->verify
register-- withpassword -->verify
passkey-- notVerified --> verify
verify --> B[signedin]
```
### /loginname
This page shows a loginname field and Identity Providers to login or register.
If `loginSettings(org?).allowRegister` is `true`, it also shows a link to jump to /register
<img src="./screenshots/loginname.png" alt="/loginame" width="400px" />
Requests to the APIs made:
- `getLoginSettings(org?)`
- `getLegalAndSupportSettings(org?)`
- `getIdentityProviders(org?)`
- `getBrandingSettings(org?)`
- `getActiveIdentityProviders(org?)`
- `startIdentityProviderFlow`
- `listUsers(org?)`
- `listAuthenticationMethodTypes`
- `getOrgsByDomain`
- `createSession()`
- `getSession()`
After a loginname is entered, a `listUsers` request is made using the loginName query to identify already registered users.
**USER FOUND:** If only one user is found, we query `listAuthenticationMethodTypes` to identify future steps.
If no authentication methods are found, we render an error stating: _User has no available authentication methods._ (exception see below.)
Now if only one method is found, we continue with the corresponding step (/password, /passkey).
If multiple methods are set, we prefer passkeys over any other method, so we redirect to /passkey, second option is IDP, and third is password.
If password is the next step, we check `loginSettings.passkeysType` for PasskeysType.ALLOWED, and prompt the user to setup passkeys afterwards.
**NO USER FOUND:** If no user is found, we check whether registering is allowed using `loginSettings.allowRegister`.
If `loginSettings?.allowUsernamePassword` is not allowed we continue to check for available IDPs. If a single IDP is available, we directly redirect the user to signup.
If no single IDP is set, we check for `loginSettings.allowUsernamePassword` and if no organization is set as context, we check whether we can discover a organization from the loginname of the user (using: `getOrgsByDomain`). Then if an organization is found, we check whether domainDiscovery is allowed on it and redirect the user to /register page including the discovered domain or without.
If no previous condition is met we throw an error stating the user was not found.
**EXCEPTIONS:** If the outcome after this order produces a no authentication methods found, or user not found, we check whether `loginSettings?.ignoreUnknownUsernames` is set to `true` as in this case we redirect to the /password page regardless (to prevent username guessing).
> NOTE: This page at this stage beeing ignores local sessions and executes a reauthentication. This is a feature which is not implemented yet.
> NOTE: We ignore `loginSettings.allowExternalIdp` as the information whether IDPs are available comes as response from `getActiveIdentityProviders(org?)`. If a user has a cookie for the same loginname, a new session is created regardless and overwrites the old session. The old session is not deleted from the login as for now.
> NOTE: `listAuthenticationMethodTypes()` does not consider different domains for u2f methods or passkeys. The check whether a user should be redirected to one of the pages `/passkey` or `/u2f`, should be extended to use a domain filter (https://github.com/zitadel/zitadel/issues/8615)
### /password
This page shows a password field to hydrate the current session with password as a factor.
Below the password field, a reset password link is shown which allows to send a reset email.
<img src="./screenshots/password.png" alt="/password" width="400px" />
Requests to the APIs made:
- `getLoginSettings(org?)`
- `getBrandingSettings(org?)`
- `listAuthenticationMethodTypes`
- `getSession()`
- `updateSession()`
- `listUsers()`
- `getUserById()`
**MFA AVAILABLE:** After the password has been submitted, additional authentication methods are loaded.
If the user has set up an additional **single** second factor, it is redirected to add the next factor. Depending on the available method he is redirected to `/otp/time-based`,`/otp/sms?`, `/otp/email?` or `/u2f?`. If the user has multiple second factors, he is redirected to `/mfa` to select his preferred method to continue.
**NO MFA, USER STATE INITIAL** If the user has no MFA methods and is in an initial state, we redirect to `/password/change` where a new password can be set.
**NO MFA, FORCE MFA:** If no MFA method is available, and the settings force MFA, the user is sent to `/mfa/set` which prompts to setup a second factor.
**PROMPT PASSKEY** If the settings do not enforce MFA, we check if passkeys are allowed with `loginSettings?.passkeysType == PasskeysType.ALLOWED` and redirect the user to `/passkey/set` if no passkeys are setup. This step can be skipped.
If none of the previous conditions apply, we continue to sign in.
> NOTE: `listAuthenticationMethodTypes()` does not consider different domains for u2f methods or passkeys. The check whether a user should be redirected to one of the pages `/passkey` or `/u2f`, should be extended to use a domain filter (https://github.com/zitadel/zitadel/issues/8615)
### /password/change
This page allows to change the password. It is used after a user is in an initial state and is required to change the password, or it can be directly invoked with an active session.
<img src="./screenshots/password_change.png" alt="/password/change" width="400px" />
Requests to the APIs made:
- `getLoginSettings(org?)`
- `getPasswordComplexitySettings(user?)`
- `getBrandingSettings(org?)`
- `getSession()`
- `setPassword()`
> NOTE: The request to change the password is using the session of the user itself not the service user, therefore no code is required.
### /password/set
This page allows to set a password. It is used after a user has requested to reset the password on the `/password` page.
<img src="./screenshots/password_set.png" alt="/password/set" width="400px" />
Requests to the APIs made:
- `getLoginSettings(org?)`
- `getPasswordComplexitySettings(user?)`
- `getBrandingSettings(org?)`
- `getUserByID()`
- `setPassword()`
The page allows to enter a code or be invoked directly from a email link which prefills the code. The user can enter a new password and submit.
### /otp/[method]
This page shows a code field to check an otp method. The session of the user is then hydrated with the respective factor. Supported methods are `time-based`, `sms` and `email`.
<img src="./screenshots/otp.png" alt="/otp/[method]" width="400px" />
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getSession()`
- `updateSession()`
If `email` or `sms` is requested as method, the current session of the user is updated to request the challenge. This will trigger an email or sms which can be entered in the code field.
The `time-based` (TOTP) method does not require a trigger, therefore no `updateSession()` is performed and no resendLink under the code field is shown.
The submission of the code updates the session and continues to sign in the user.
### /u2f
This page requests a webAuthN challenge for the user and updates the session afterwards.
<img src="./screenshots/u2f.png" alt="/u2f" width="400px" />
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getSession()`
- `updateSession()`
When updating the session for the webAuthN challenge, we set `userVerificationRequirement` to `UserVerificationRequirement.DISCOURAGED` as this will request the webAuthN method as second factor and not as primary method.
After updating the session, the user is **always** signed in. :warning: required as this page is a follow up for setting up a u2f method.
### /passkey
This page requests a webAuthN challenge for the user and updates the session afterwards.
It is invoked directly after setting up a passkey `/passkey/set` or when loggin in a user after `/loginname`.
<img src="./screenshots/passkey.png" alt="/passkey" width="400px" />
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getSession()`
- `updateSession()`
When updating the session for the webAuthN challenge, we set `userVerificationRequirement` to `UserVerificationRequirement.REQUIRED` as this will request the webAuthN method as primary method to login.
After updating the session, the user is **always** signed in. :warning: required as this page is a follow up for setting up a passkey
> NOTE: This page currently does not check whether a user contains passkeys. If this method is not available, this page should not be used.
### /mfa/set
This page loads login settings and the authentication methods for a user and shows setup options.
<img src="./screenshots/mfaset.png" alt="/mfa/set" width="400px" />
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getLoginSettings(user.org)` :warning: context taken from session
- `getSession()`
- `listAuthenticationMethodTypes()`
- `getUserByID()`
If a user has already setup a certain method, a checkbox is shown alongside the button and the button is disabled.
OTP Email and OTP SMS only show up if the user has verified email or phone.
If the user chooses a method he is redirected to one of `/otp/time-based/set`, `/u2f/set`, `/otp/email/set`, or `/otp/sms/set`.
At the moment, U2F methods are hidden if a method is already added on the users resource. Reasoning is that the page should only be invoked for prompts. A self service page which shows up multiple u2f factors is implemented at a later stage.
> NOTE: The session and therefore the user factor defines which login settings are checked for available options.
> NOTE: `listAuthenticationMethodTypes()` does not consider different domains for u2f or passkeys. The check whether a user should be redirected to one of the pages `/passkey/set` or `/u2f/set`, should be extended to use a domain filter (https://github.com/zitadel/zitadel/issues/8615)
### /passkey/set
This page sets a passkey method for a user. This page can be either enforced, or optional depending on the Login Settings.
<!-- screen is the same -->
<img src="./screenshots/u2fset.png" alt="/passkey/set" width="400px" />
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getSession()`
- `createPasskeyRegistrationLink()` TODO: check if this can be used with the session token (mfa required (AUTHZ-Kl3p0))
- `registerPasskey()`
- `verifyPasskey()`
If the loginname decides to redirect the user to this page, a button to skip appears which will sign the user in afterwards.
After a passkey is registered, we redirect the user to `/passkey` to verify it again and sign in with the new method. The `createPasskeyRegistrationLink()` uses the token of the session which is determined by the flow.
> NOTE: this page allows passkeys to be created only if the current session is valid (self service), or no authentication method is set (register). TODO: to be implemented.
> NOTE: Redirecting the user to `/passkey` will not be required in future and the currently used session will be hydrated directly after registering. (https://github.com/zitadel/zitadel/issues/8611)
### /otp/time-based/set
This page registers a time based OTP method for a user.
<img src="./screenshots/otpset.png" alt="/otp/time-based/set" width="400px" />
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getSession()`
- `registerTOTP()`
- `verifyTOTP()`
After the setup is done, the user is redirected to verify the TOTP method on `/otp/time-based`.
> NOTE: Redirecting the user to `/otp/time-based` will not be required in future and the currently used session will be hydrated directly. (https://github.com/zitadel/zitadel/issues/8611)
### /otp/email/set /otp/sms/set
This page registers either an Email OTP method or SMS OTP method for a user.
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getSession()`
- `addOTPEmail()` / `addOTPSMS()`
This page directly calls `addOTPEmail()` or `addOTPSMS()` when invoked and shows a success message.
Right afterwards, redirects to verify the method.
### /u2f/set
This page registers a U2F method for a user.
<img src="./screenshots/u2fset.png" alt="/u2f/set" width="400px" />
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getSession()`
- `registerU2F()` :warning: TODO: check if this can be used with the session token (mfa required (AUTHZ-Kl3p0))
- `verifyU2FRegistration()`
After a u2f method is registered, we redirect the user to `/passkey` to verify it again and sign in with the new method. The `createPasskeyRegistrationLink()` uses the token of the session which is determined by the flow.
> NOTE: Redirecting the user to `/passkey` will not be required in future and the currently used session will be hydrated directly after registering. (https://github.com/zitadel/zitadel/issues/8611)
### /register
This page shows a register page, which gets firstname and lastname of a user as well as the email. It offers to setup a user, using password or passkeys.
<img src="./screenshots/register.png" alt="/register" width="400px" />
<img src="./screenshots/register_password.png" alt="register with password" width="400px" />
Requests to the APIs made:
- `listOrganizations()` :warning: TODO: determine the default organization if no context is set
- `getLegalAndSupportSettings(org)`
- `getPasswordComplexitySettings()`
- `getBrandingSettings()`
- `addHumanUser()`
- `createSession()`
- `getSession()`
To register a user, the organization where the resource will be created is determined first. If no context is provided via url, we fall back to the default organization of the instance.
**PASSWORD:** If a password is set, the user is created as a resource, then a session using the password check is created immediately. After creating the session, the user is directly logged in and eventually redirected back to the application.
**PASSKEY:** If passkey is selected, the user is created as a resource first, then a session using the userId is created immediately. This session does not yet contain a check, we therefore redirect the user to setup a passkey at `/passkey/set`. As the passkey set page verifies the passkey right afterwards, the process ends with a signed in user.
> NOTE: https://github.com/zitadel/zitadel/issues/8616 to determine the default organization of an instance must be implemented in order to correctly use the legal-, login-, branding- and complexitysettings.
> NOTE: TODO: check which methods are allowed in the login settings, loginSettings.allowUsernamePassword / check for passkey
### /idp
This page doubles as /loginname but limits it to choose from IDPs
<img src="./screenshots/idp.png" alt="/idp" width="400px" />
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getActiveIdentityProviders(org?)`
- `startIdentityProviderFlow()`
### /idp/[method]/success /idp/[method]/failure
Both /success and /failure pages are designed to intercept the responses from the IDPs and decide on how to continue with the process.
### /verify
This page verifies the email to be valid. It page of the login can also be invoked without an active session.
The context of the user is taken from the url and is set in the email template.
<img src="./screenshots/accounts.png" alt="/accounts" width="400px" />
Requests to the APIs made:
- `getBrandingSettings(org?)`
- `getLoginSettings(org?)`
- `verifyEmail()`
If the page is invoked with an active session (right after a register with password), the user is signed in or redirected to the loginname if no context is known.
> NOTE: This page will be extended to support invitations. In such case, authentication methods of the user are loaded and if none available, shown as possible next step (`/passkey/set`, `password/set`).
### /accounts
This page shows an overview of all current sessions.
Sessions with invalid token show a red dot on the right side, Valid session a green dot, and its last verified date.
<img src="./screenshots/accounts.png" alt="/accounts" width="400px" />
This page is a starting point for self management, reauthentication, or can be used to clear local sessions.
This page is also shown if used with OIDC and `prompt: select_account`.
On all pages, where the current user is shown, you can jump to this page. This way, a session can quickly be reused if valid.
<img src="./screenshots/accounts_jumpto.png" alt="jump to accounts" width="250px" />
### /signedin
This is a success page which shows a completed login flow for a user, which did navigate to the login without a OIDC auth requrest. From here device authorization flows are completed. It checks if the requestId param of starts with `device_` and then executes the `authorizeOrDenyDeviceAuthorization` command.
<img src="./screenshots/signedin.png" alt="/signedin" width="400px" />
In future, self service options to jump to are shown below, like:
- change password
- setup passkeys
- setup mfa
- change profile
- logout
> NOTE: This page has to be explicitly enabled or act as a fallback if no default redirect is set.
## Currently NOT Supported
- forceMFA on login settings is not checked for IDPs
Also note that IDP logins are considered as valid MFA. An additional MFA check will be implemented in future if enforced.

View File

@@ -26,7 +26,7 @@
"@angular/platform-browser-dynamic": "^16.2.12",
"@angular/router": "^16.2.12",
"@angular/service-worker": "^16.2.12",
"@bufbuild/protobuf": "^2.2.2",
"@bufbuild/protobuf": "^2.6.1",
"@connectrpc/connect": "^2.0.0",
"@connectrpc/connect-web": "^2.0.0",
"@ctrl/ngx-codemirror": "^6.1.0",
@@ -67,7 +67,7 @@
"@angular/cli": "^16.2.15",
"@angular/compiler-cli": "^16.2.5",
"@angular/language-service": "^18.2.4",
"@bufbuild/buf": "^1.41.0",
"@bufbuild/buf": "^1.55.1",
"@netlify/framework-info": "^9.8.13",
"@types/file-saver": "^2.0.7",
"@types/google-protobuf": "^3.15.3",

View File

@@ -12,8 +12,6 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { State, WebKey } from '@zitadel/proto/zitadel/webkey/v2beta/key_pb';
import { CreateWebKeyRequestSchema } from '@zitadel/proto/zitadel/webkey/v2beta/webkey_service_pb';
import { RSAHasher, RSABits, ECDSACurve } from '@zitadel/proto/zitadel/webkey/v2beta/key_pb';
import { NewFeatureService } from 'src/app/services/new-feature.service';
import { ActivatedRoute, Router } from '@angular/router';
const CACHE_WARNING_MS = 5 * 60 * 1000; // 5 minutes

View File

@@ -412,7 +412,10 @@ export class UserDetailComponent implements OnInit {
public sendSetPasswordNotification(user: UserV2): void {
this.newMgmtService
.sendHumanResetPasswordNotification(user.userId, SendHumanResetPasswordNotificationRequest_Type.EMAIL)
.sendHumanResetPasswordNotification({
userId: user.userId,
type: SendHumanResetPasswordNotificationRequest_Type.EMAIL,
})
.then(() => {
this.toast.showInfo('USER.TOAST.PASSWORDNOTIFICATIONSENT', true);
this.refreshChanges$.emit();

View File

@@ -5,6 +5,7 @@ import {
CreateTargetRequestSchema,
CreateTargetResponse,
DeleteTargetRequestSchema,
DeleteTargetResponse,
GetTargetRequestSchema,
GetTargetResponse,
ListExecutionFunctionsRequestSchema,
@@ -37,7 +38,7 @@ export class ActionService {
return this.grpcService.actionNew.createTarget(req);
}
public deleteTarget(req: MessageInitShape<typeof DeleteTargetRequestSchema>): Promise<CreateTargetResponse> {
public deleteTarget(req: MessageInitShape<typeof DeleteTargetRequestSchema>): Promise<DeleteTargetResponse> {
return this.grpcService.actionNew.deleteTarget(req);
}

View File

@@ -16,12 +16,9 @@ import { ExhaustedGrpcInterceptor } from './interceptors/exhausted.grpc.intercep
import { I18nInterceptor } from './interceptors/i18n.interceptor';
import { NewConnectWebOrgInterceptor, OrgInterceptor, OrgInterceptorProvider } from './interceptors/org.interceptor';
import { UserServiceClient } from '../proto/generated/zitadel/user/v2/User_serviceServiceClientPb';
//@ts-ignore
import { createFeatureServiceClient, createUserServiceClient, createSessionServiceClient } from '@zitadel/client/v2';
//@ts-ignore
import { createAuthServiceClient, createManagementServiceClient } from '@zitadel/client/v1';
import { createGrpcWebTransport } from '@connectrpc/connect-web';
// @ts-ignore
import { createClientFor } from '@zitadel/client';
import { WebKeyService } from '@zitadel/proto/zitadel/webkey/v2beta/webkey_service_pb';
@@ -77,30 +74,10 @@ export class GrpcService {
],
};
this.auth = new AuthServiceClient(
env.api,
null,
// @ts-ignore
interceptors,
);
this.mgmt = new ManagementServiceClient(
env.api,
null,
// @ts-ignore
interceptors,
);
this.admin = new AdminServiceClient(
env.api,
null,
// @ts-ignore
interceptors,
);
this.user = new UserServiceClient(
env.api,
null,
// @ts-ignore
interceptors,
);
this.auth = new AuthServiceClient(env.api, null, interceptors);
this.mgmt = new ManagementServiceClient(env.api, null, interceptors);
this.admin = new AdminServiceClient(env.api, null, interceptors);
this.user = new UserServiceClient(env.api, null, interceptors);
const transport = createGrpcWebTransport({
baseUrl: env.api,

View File

@@ -44,27 +44,27 @@ export class NewAuthService {
}
public listMyMultiFactors(): Promise<ListMyAuthFactorsResponse> {
return this.grpcService.authNew.listMyAuthFactors(create(ListMyAuthFactorsRequestSchema), null);
return this.grpcService.authNew.listMyAuthFactors(create(ListMyAuthFactorsRequestSchema));
}
public removeMyAuthFactorOTPSMS(): Promise<RemoveMyAuthFactorOTPSMSResponse> {
return this.grpcService.authNew.removeMyAuthFactorOTPSMS(create(RemoveMyAuthFactorOTPSMSRequestSchema), null);
return this.grpcService.authNew.removeMyAuthFactorOTPSMS(create(RemoveMyAuthFactorOTPSMSRequestSchema));
}
public getMyLoginPolicy(): Promise<GetMyLoginPolicyResponse> {
return this.grpcService.authNew.getMyLoginPolicy(create(GetMyLoginPolicyRequestSchema), null);
return this.grpcService.authNew.getMyLoginPolicy(create(GetMyLoginPolicyRequestSchema));
}
public removeMyMultiFactorOTP(): Promise<RemoveMyAuthFactorOTPResponse> {
return this.grpcService.authNew.removeMyAuthFactorOTP(create(RemoveMyAuthFactorOTPRequestSchema), null);
return this.grpcService.authNew.removeMyAuthFactorOTP(create(RemoveMyAuthFactorOTPRequestSchema));
}
public removeMyMultiFactorU2F(tokenId: string): Promise<RemoveMyAuthFactorU2FResponse> {
return this.grpcService.authNew.removeMyAuthFactorU2F(create(RemoveMyAuthFactorU2FRequestSchema, { tokenId }), null);
return this.grpcService.authNew.removeMyAuthFactorU2F(create(RemoveMyAuthFactorU2FRequestSchema, { tokenId }));
}
public removeMyAuthFactorOTPEmail(): Promise<RemoveMyAuthFactorOTPEmailResponse> {
return this.grpcService.authNew.removeMyAuthFactorOTPEmail(create(RemoveMyAuthFactorOTPEmailRequestSchema), null);
return this.grpcService.authNew.removeMyAuthFactorOTPEmail(create(RemoveMyAuthFactorOTPEmailRequestSchema));
}
public getMyPasswordComplexityPolicy(): Promise<GetMyPasswordComplexityPolicyResponse> {

View File

@@ -64,11 +64,10 @@ export class NewMgmtService {
}
public sendHumanResetPasswordNotification(
userId: string,
type: SendHumanResetPasswordNotificationRequest_Type,
req: MessageInitShape<typeof SendHumanResetPasswordNotificationRequestSchema>,
): Promise<SendHumanResetPasswordNotificationResponse> {
return this.grpcService.mgmtNew.sendHumanResetPasswordNotification(
create(SendHumanResetPasswordNotificationRequestSchema, { userId, type }),
create(SendHumanResetPasswordNotificationRequestSchema, req),
);
}

View File

@@ -16,18 +16,18 @@ export class WebKeysService {
constructor(private readonly grpcService: GrpcService) {}
public ListWebKeys(): Promise<ListWebKeysResponse> {
return this.grpcService.webKey.listWebKeys({});
return this.grpcService.webKey['listWebKeys']({});
}
public DeleteWebKey(id: string): Promise<DeleteWebKeyResponse> {
return this.grpcService.webKey.deleteWebKey({ id });
return this.grpcService.webKey['deleteWebKey']({ id });
}
public CreateWebKey(req: MessageInitShape<typeof CreateWebKeyRequestSchema>): Promise<CreateWebKeyResponse> {
return this.grpcService.webKey.createWebKey(req);
return this.grpcService.webKey['createWebKey'](req);
}
public ActivateWebKey(id: string): Promise<ActivateWebKeyResponse> {
return this.grpcService.webKey.activateWebKey({ id });
return this.grpcService.webKey['activateWebKey']({ id });
}
}

View File

@@ -0,0 +1,6 @@
{
"name": "@zitadel/client-node",
"main": "../dist/node.js",
"types": "../dist/node.d.ts",
"type": "module"
}

View File

@@ -13,31 +13,53 @@
"require": "./dist/index.cjs"
},
"./v1": {
"types": "./dist/v1.d.ts",
"types": {
"import": "./dist/v1.d.ts",
"require": "./dist/v1.d.cts",
"default": "./dist/v1.d.ts"
},
"import": "./dist/v1.js",
"require": "./dist/v1.cjs"
},
"./v2": {
"types": "./dist/v2.d.ts",
"types": {
"import": "./dist/v2.d.ts",
"require": "./dist/v2.d.cts",
"default": "./dist/v2.d.ts"
},
"import": "./dist/v2.js",
"require": "./dist/v2.cjs"
},
"./v3alpha": {
"types": "./dist/v3alpha.d.ts",
"types": {
"import": "./dist/v3alpha.d.ts",
"require": "./dist/v3alpha.d.cts",
"default": "./dist/v3alpha.d.ts"
},
"import": "./dist/v3alpha.js",
"require": "./dist/v3alpha.cjs"
},
"./node": {
"types": "./dist/node.d.ts",
"types": {
"import": "./dist/node.d.ts",
"require": "./dist/node.d.cts",
"default": "./dist/node.d.ts"
},
"import": "./dist/node.js",
"require": "./dist/node.cjs"
},
"./web": {
"types": "./dist/web.d.ts",
"types": {
"import": "./dist/web.d.ts",
"require": "./dist/web.d.cts",
"default": "./dist/web.d.ts"
},
"import": "./dist/web.js",
"require": "./dist/web.cjs"
}
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist/**"
],

View File

@@ -0,0 +1,6 @@
{
"name": "@zitadel/client-v1",
"main": "../dist/v1.js",
"types": "../dist/v1.d.ts",
"type": "module"
}

View File

@@ -0,0 +1,6 @@
{
"name": "@zitadel/client-v2",
"main": "../dist/v2.js",
"types": "../dist/v2.d.ts",
"type": "module"
}

View File

@@ -0,0 +1,6 @@
{
"name": "@zitadel/client-v3alpha",
"main": "../dist/v3alpha.js",
"types": "../dist/v3alpha.d.ts",
"type": "module"
}

View File

@@ -0,0 +1,6 @@
{
"name": "@zitadel/client-web",
"main": "../dist/web.js",
"types": "../dist/web.d.ts",
"type": "module"
}

View File

@@ -3,3 +3,6 @@ google
protoc-gen-openapiv2
validate
node_modules
cjs
es
types

View File

@@ -3,8 +3,24 @@ managed:
enabled: true
plugins:
- remote: buf.build/bufbuild/es:v2.2.0
out: .
out: es
include_imports: true
opt:
- target=js
- json_types=true
- import_extension=js
- remote: buf.build/bufbuild/es:v2.2.0
out: cjs
include_imports: true
opt:
- target=js
- json_types=true
- import_extension=js
- js_import_style=legacy_commonjs
- remote: buf.build/bufbuild/es:v2.2.0
out: types
include_imports: true
opt:
- target=dts
- json_types=true
- import_extension=js

View File

@@ -6,21 +6,76 @@
"access": "public"
},
"type": "module",
"files": [
"zitadel/**",
"validate/**",
"google/**",
"protoc-gen-openapiv2/**"
],
"main": "./cjs/index.js",
"types": "./types/index.d.ts",
"exports": {
"./zitadel/*": {
"types": "./types/zitadel/*.d.ts",
"import": "./es/zitadel/*.js",
"require": "./cjs/zitadel/*.js"
},
"./zitadel/*.js": {
"types": "./types/zitadel/*.d.ts",
"import": "./es/zitadel/*.js",
"require": "./cjs/zitadel/*.js"
},
"./validate/*": {
"types": "./types/validate/*.d.ts",
"import": "./es/validate/*.js",
"require": "./cjs/validate/*.js"
},
"./validate/*.js": {
"types": "./types/validate/*.d.ts",
"import": "./es/validate/*.js",
"require": "./cjs/validate/*.js"
},
"./google/*": {
"types": "./types/google/*.d.ts",
"import": "./es/google/*.js",
"require": "./cjs/google/*.js"
},
"./google/*.js": {
"types": "./types/google/*.d.ts",
"import": "./es/google/*.js",
"require": "./cjs/google/*.js"
},
"./protoc-gen-openapiv2/*": {
"types": "./types/protoc-gen-openapiv2/*.d.ts",
"import": "./es/protoc-gen-openapiv2/*.js",
"require": "./cjs/protoc-gen-openapiv2/*.js"
},
"./protoc-gen-openapiv2/*.js": {
"types": "./types/protoc-gen-openapiv2/*.d.ts",
"import": "./es/protoc-gen-openapiv2/*.js",
"require": "./cjs/protoc-gen-openapiv2/*.js"
}
},
"typesVersions": {
"*": {
"zitadel/*": [
"./types/zitadel/*"
],
"validate/*": [
"./types/validate/*"
],
"google/*": [
"./types/google/*"
],
"protoc-gen-openapiv2/*": [
"./types/protoc-gen-openapiv2/*"
]
}
},
"sideEffects": false,
"scripts": {
"generate": "buf generate ../../proto",
"clean": "rm -rf zitadel .turbo node_modules google protoc-gen-openapiv2 validate"
"clean": "rm -rf zitadel .turbo node_modules google protoc-gen-openapiv2 validate cjs types es"
},
"dependencies": {
"@bufbuild/protobuf": "^2.2.2"
"@bufbuild/protobuf": "^2.6.1"
},
"devDependencies": {
"@bufbuild/buf": "^1.53.0"
"@bufbuild/buf": "^1.55.1",
"glob": "^11.0.0"
}
}

View File

@@ -2,7 +2,15 @@
"extends": ["//"],
"tasks": {
"generate": {
"outputs": ["zitadel/**"]
"outputs": [
"zitadel/**",
"google/**",
"validate/**",
"protoc-gen-openapiv2/**",
"cjs/**",
"es/**",
"types/**"
]
}
}
}

72
pnpm-lock.yaml generated
View File

@@ -270,7 +270,7 @@ importers:
specifier: ^16.2.12
version: 16.2.12(@angular/common@16.2.12(@angular/core@16.2.12(rxjs@7.8.2)(zone.js@0.13.3))(rxjs@7.8.2))(@angular/core@16.2.12(rxjs@7.8.2)(zone.js@0.13.3))
'@bufbuild/protobuf':
specifier: ^2.2.2
specifier: ^2.6.1
version: 2.6.2
'@connectrpc/connect':
specifier: ^2.0.0
@@ -388,7 +388,7 @@ importers:
specifier: ^18.2.4
version: 18.2.13
'@bufbuild/buf':
specifier: ^1.41.0
specifier: ^1.55.1
version: 1.55.1
'@netlify/framework-info':
specifier: ^9.8.13
@@ -640,12 +640,15 @@ importers:
packages/zitadel-proto:
dependencies:
'@bufbuild/protobuf':
specifier: ^2.2.2
specifier: ^2.6.1
version: 2.6.2
devDependencies:
'@bufbuild/buf':
specifier: ^1.53.0
specifier: ^1.55.1
version: 1.55.1
glob:
specifier: ^11.0.0
version: 11.0.3
packages:
@@ -3102,6 +3105,14 @@ packages:
'@inkeep/cxkit-types@0.5.96':
resolution: {integrity: sha512-ljOudxIY5JC4LLXyAi5hNUfJcQGirmBv4Okup0EczF4tosSDZFG6fzLYXOZ/wNvJ4vNq+TGsXu2yJuAvp9crMA==}
'@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22}
'@isaacs/brace-expansion@5.0.0':
resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==}
engines: {node: 20 || >=22}
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@@ -8382,6 +8393,11 @@ packages:
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
hasBin: true
glob@11.0.3:
resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==}
engines: {node: 20 || >=22}
hasBin: true
glob@7.1.4:
resolution: {integrity: sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==}
deprecated: Glob versions prior to v9 are no longer supported
@@ -9211,6 +9227,10 @@ packages:
jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
jackspeak@4.1.1:
resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==}
engines: {node: 20 || >=22}
jake@10.9.2:
resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
engines: {node: '>=10'}
@@ -9747,6 +9767,10 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lru-cache@11.1.0:
resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==}
engines: {node: 20 || >=22}
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
@@ -10294,6 +10318,10 @@ packages:
minimalistic-assert@1.0.1:
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
minimatch@10.0.3:
resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==}
engines: {node: 20 || >=22}
minimatch@3.0.5:
resolution: {integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==}
@@ -11002,6 +11030,10 @@ packages:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
path-scurry@2.0.0:
resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==}
engines: {node: 20 || >=22}
path-to-regexp@0.1.12:
resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==}
@@ -18343,6 +18375,12 @@ snapshots:
'@inkeep/cxkit-types@0.5.96': {}
'@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.0':
dependencies:
'@isaacs/balanced-match': 4.0.1
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
@@ -22829,7 +22867,7 @@ snapshots:
copy-webpack-plugin@11.0.0(webpack@5.100.2(@swc/core@1.13.2(@swc/helpers@0.5.17))):
dependencies:
fast-glob: 3.3.3
fast-glob: 3.3.1
glob-parent: 6.0.2
globby: 13.2.2
normalize-path: 3.0.0
@@ -24978,6 +25016,15 @@ snapshots:
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
glob@11.0.3:
dependencies:
foreground-child: 3.3.1
jackspeak: 4.1.1
minimatch: 10.0.3
minipass: 7.1.2
package-json-from-dist: 1.0.1
path-scurry: 2.0.0
glob@7.1.4:
dependencies:
fs.realpath: 1.0.0
@@ -26028,6 +26075,10 @@ snapshots:
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
jackspeak@4.1.1:
dependencies:
'@isaacs/cliui': 8.0.2
jake@10.9.2:
dependencies:
async: 3.2.6
@@ -26639,6 +26690,8 @@ snapshots:
lru-cache@10.4.3: {}
lru-cache@11.1.0: {}
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
@@ -27773,6 +27826,10 @@ snapshots:
minimalistic-assert@1.0.1: {}
minimatch@10.0.3:
dependencies:
'@isaacs/brace-expansion': 5.0.0
minimatch@3.0.5:
dependencies:
brace-expansion: 1.1.12
@@ -28686,6 +28743,11 @@ snapshots:
lru-cache: 10.4.3
minipass: 7.1.2
path-scurry@2.0.0:
dependencies:
lru-cache: 11.1.0
minipass: 7.1.2
path-to-regexp@0.1.12: {}
path-to-regexp@1.9.0: