+
diff --git a/console/src/app/modules/show-key-dialog/show-key-dialog.component.ts b/console/src/app/modules/show-key-dialog/show-key-dialog.component.ts
index e6655ae29b..7466a7d969 100644
--- a/console/src/app/modules/show-key-dialog/show-key-dialog.component.ts
+++ b/console/src/app/modules/show-key-dialog/show-key-dialog.component.ts
@@ -11,6 +11,7 @@ import { InfoSectionType } from '../info-section/info-section.component';
})
export class ShowKeyDialogComponent {
public keyResponse!: AddMachineKeyResponse.AsObject | AddAppKeyResponse.AsObject;
+ public expirationDate: string = '';
public InfoSectionType: any = InfoSectionType;
constructor(
@@ -18,6 +19,10 @@ export class ShowKeyDialogComponent {
@Inject(MAT_DIALOG_DATA) public data: any,
) {
this.keyResponse = data.key;
+ if (this.keyResponse.keyDetails) {
+ const keyDetails: { expirationDate: string } = JSON.parse(atob(this.keyResponse.keyDetails.toString()));
+ this.expirationDate = keyDetails.expirationDate;
+ }
}
public saveFile(): void {
diff --git a/docs/docs/guides/integrate/private-key-jwt.md b/docs/docs/guides/integrate/private-key-jwt.md
index 54288382e9..620293bddf 100644
--- a/docs/docs/guides/integrate/private-key-jwt.md
+++ b/docs/docs/guides/integrate/private-key-jwt.md
@@ -4,6 +4,7 @@ sidebar_label: Service Users
---
This is a guide on how to create service users in ZITADEL. You can read more about users [here](/concepts/structure/users.md).
+
## Create a Service User
1. Navigate to Service Users
@@ -32,18 +33,22 @@ In this step we will authenticate a service user and receive an access_token to
### 1. Generate a private-public key pair in ZITADEL
-Select your service user and in the section KEYS click **New**. Enter an expiration date and click **Add**. Make sure to download the json by clicking **Download**.
+Select your service user and in the section KEYS click **New**. Enter an optional expiration date and click **Add**. Make sure to download the json by clicking **Download**.
+
+:::note
+If you specify an expiration date, note that the key will expire at midnight that day
+:::
![Create private key](/img/console_serviceusers_new_key.gif)
-The downloaded json should look something like outlined below. The value of `key` contains the *private* key for your service account. Please make sure to keep this key securely stored and handle with care. The public key is automatically stored in ZITADEL.
+The downloaded json should look something like outlined below. The value of `key` contains the _private_ key for your service account. Please make sure to keep this key securely stored and handle with care. The public key is automatically stored in ZITADEL.
```json
{
- "type":"serviceaccount",
- "keyId":"100509901696068329",
- "key":"-----BEGIN RSA PRIVATE KEY----- [...] -----END RSA PRIVATE KEY-----\n",
- "userId":"100507859606888466"
+ "type": "serviceaccount",
+ "keyId": "100509901696068329",
+ "key": "-----BEGIN RSA PRIVATE KEY----- [...] -----END RSA PRIVATE KEY-----\n",
+ "userId": "100507859606888466"
}
```
@@ -55,8 +60,8 @@ Header
```json
{
- "alg": "RS256",
- "kid":"100509901696068329"
+ "alg": "RS256",
+ "kid": "100509901696068329"
}
```
@@ -74,11 +79,11 @@ Payload
}
```
-* `iss` represents the requesting party, i.e. the owner of the private key. In this case the value of `userId` from the downloaded JSON.
-* `sub` represents the application. Set the value also to the value of `userId`
-* `aud` must be ZITADEL's issuing domain
-* `iat` is a unix timestamp of the creation signing time of the JWT, e.g. now and must not be older than 1 hour ago
-* `exp` is the unix timestamp of expiry of this assertion
+- `iss` represents the requesting party, i.e. the owner of the private key. In this case the value of `userId` from the downloaded JSON.
+- `sub` represents the application. Set the value also to the value of `userId`
+- `aud` must be ZITADEL's issuing domain
+- `iat` is a unix timestamp of the creation signing time of the JWT, e.g. now and must not be older than 1 hour ago
+- `exp` is the unix timestamp of expiry of this assertion
Please refer to [JWT_with_Private_Key](/apis/openidoauth/authn-methods#jwt-with-private-key) in the documentation for further information.
@@ -99,11 +104,11 @@ curl --request POST \
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
+- `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
-You should receive a successful response with `access_token`, `token_type` and time to expiry in seconds as `expires_in`.
+You should receive a successful response with `access_token`, `token_type` and time to expiry in seconds as `expires_in`.
```bash
HTTP/1.1 200 OK
@@ -142,11 +147,11 @@ Content-Type: application/json
## Summary
-* With service users you can secure machine-to-machine communication
-* Because there is no interactive logon, you need to use a JWT signed with your private key to authorize the user
-* After successful authorization you can use an access token like for human users
+- With service users you can secure machine-to-machine communication
+- Because there is no interactive logon, you need to use a JWT signed with your private key to authorize the user
+- After successful authorization you can use an access token like for human users
Where to go from here:
-* Management API
-* Securing backend API
+- Management API
+- Securing backend API
diff --git a/internal/command/user_machine_key.go b/internal/command/user_machine_key.go
index 1e6ca56f24..d092cc54ef 100644
--- a/internal/command/user_machine_key.go
+++ b/internal/command/user_machine_key.go
@@ -56,7 +56,7 @@ func (key *MachineKey) Detail() ([]byte, error) {
return nil, zerrors.ThrowPreconditionFailed(nil, "KEY-sp2l2m", "Errors.Internal")
}
if key.Type == domain.AuthNKeyTypeJSON {
- return domain.MachineKeyMarshalJSON(key.KeyID, key.PrivateKey, key.AggregateID)
+ return domain.MachineKeyMarshalJSON(key.KeyID, key.PrivateKey, key.ExpirationDate, key.AggregateID)
}
return nil, zerrors.ThrowPreconditionFailed(nil, "KEY-dsg52", "Errors.Internal")
}
diff --git a/internal/domain/machine_key.go b/internal/domain/machine_key.go
index ea7777d6da..5be2eb58fe 100644
--- a/internal/domain/machine_key.go
+++ b/internal/domain/machine_key.go
@@ -42,7 +42,7 @@ func (key *MachineKey) Detail() ([]byte, error) {
}
func (key *MachineKey) MarshalJSON() ([]byte, error) {
- return MachineKeyMarshalJSON(key.KeyID, key.PrivateKey, key.AggregateID)
+ return MachineKeyMarshalJSON(key.KeyID, key.PrivateKey, key.ExpirationDate, key.AggregateID)
}
type MachineKeyState int32
@@ -59,16 +59,18 @@ func (f MachineKeyState) Valid() bool {
return f >= 0 && f < machineKeyStateCount
}
-func MachineKeyMarshalJSON(keyID string, privateKey []byte, userID string) ([]byte, error) {
+func MachineKeyMarshalJSON(keyID string, privateKey []byte, expirationDate time.Time, userID string) ([]byte, error) {
return json.Marshal(struct {
- Type string `json:"type"`
- KeyID string `json:"keyId"`
- Key string `json:"key"`
- UserID string `json:"userId"`
+ Type string `json:"type"`
+ KeyID string `json:"keyId"`
+ Key string `json:"key"`
+ ExpirationDate time.Time `json:"expirationDate"`
+ UserID string `json:"userId"`
}{
- Type: "serviceaccount",
- KeyID: keyID,
- Key: string(privateKey),
- UserID: userID,
+ Type: "serviceaccount",
+ KeyID: keyID,
+ Key: string(privateKey),
+ ExpirationDate: expirationDate,
+ UserID: userID,
})
}