diff --git a/docs/auth/access-tokens.md b/docs/auth/access-tokens.md index 3340d777..2de6e236 100644 --- a/docs/auth/access-tokens.md +++ b/docs/auth/access-tokens.md @@ -27,6 +27,8 @@ Manage Access Tokens from [Settings > Access Tokens](https://portal.epilot.cloud By default, a new Access Token inherits the roles and permissions of the creating user. +When creating a token, you can optionally set an **expiry**. A token with an expiry is automatically invalidated once it passes; a token created without one remains valid until revoked. Setting an expiry is recommended to limit the impact of a leaked token. + ![Access Token create view](/img/create-access-token.png) :::note @@ -70,6 +72,28 @@ POST /v1/access-tokens } ``` +Set an optional expiry with the `expires_in` parameter — a number of seconds (e.g. `3600`) or a duration string with time units (e.g. `'10h'`, `'7d'`, `'2 days'`), bounded between 30 seconds and 365 days. Without `expires_in`, the token does not expire. + +```json title="Request body with expiry" +{ + "name": "Postman Access Token", + "assume_roles": ["123:owner"], + "expires_in": "30d" +} +``` + +Tokens created with `expires_in` are stored, listed, and revocable exactly like non-expiring tokens. The response includes an `expires_at` timestamp, and the token stops working — and drops out of the token list — once it expires: + +```json title="201 response for a token with expiry" +{ + "id": "api_5ZugdRXasLfWBypHi93Fk", + "created_at": "2019-08-24T14:15:22Z", + "expires_at": "2019-09-23T14:15:22.000Z", + "name": "Postman Access Token", + "assignments": ["123:owner"] +} +``` + Each Access Token generated via the API receives a unique ID. ```json title="201 response" diff --git a/docs/auth/authentication.md b/docs/auth/authentication.md index 2bfd865b..550b0927 100644 --- a/docs/auth/authentication.md +++ b/docs/auth/authentication.md @@ -12,10 +12,10 @@ Authorization: Bearer ## Getting Started -The recommended way to authenticate with epilot APIs is using **Access Tokens** — long-lived, scoped tokens designed for integrations. +The recommended way to authenticate with epilot APIs is using **Access Tokens** — scoped tokens designed for integrations. 1. Go to [Settings > Access Tokens](https://portal.epilot.cloud/app/tokens) in the epilot portal -2. Create a new token, optionally scoping it to specific roles +2. Create a new token, optionally scoping it to specific roles and setting an expiry 3. Pass the token as a bearer token in your API requests ```typescript @@ -95,7 +95,7 @@ See the [SDK documentation](/docs/sdk/overview) for the full SDK reference. epilot authentication is built on [OAuth 2.0](https://oauth.net/2/) with [Amazon Cognito User Pools](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html) as the identity provider. Each epilot tenant has its own Cognito User Pool. -When a user logs in to the epilot portal, Cognito issues short-lived OAuth tokens (60 min). For API integrations, the [Access Token service](/api/access-token) issues long-lived JWTs with claims compatible with Cognito tokens, so all epilot APIs accept them seamlessly. +When a user logs in to the epilot portal, Cognito issues short-lived OAuth tokens (60 min). For API integrations, the [Access Token service](/api/access-token) issues JWTs with claims compatible with Cognito tokens, so all epilot APIs accept them seamlessly. These tokens support an optional expiry set at creation and stay valid until revoked if none is set. All tokens are verified by the API Gateway authorizer using JWKS endpoints before reaching backend services. @@ -118,7 +118,7 @@ sequenceDiagram | Token | Lifetime | Use case | |---|---|---| -| **Access Token** | Long-lived | Server-side API integrations, scripts, third-party apps | +| **Access Token** | Configurable expiry, up to 365 days (valid until revoked if unset) | Server-side API integrations, scripts, third-party apps | | **OAuth 2.0 Token** | 60 minutes | Interactive user sessions in the epilot portal | | **Publishable Token** | Long-lived | Client-side public apps (journeys, portals) | diff --git a/docs/auth/security.md b/docs/auth/security.md index 3015b083..b417bdff 100644 --- a/docs/auth/security.md +++ b/docs/auth/security.md @@ -62,10 +62,10 @@ epilot supports multiple token types for different use cases: | Token Type | Lifetime | Use Case | |---|---|---| | **OAuth Access Token** | 60 minutes | Interactive user sessions | -| **Access Token (Long-lived)** | No expiration | Third-party integrations, automation | +| **Access Token** | Configurable expiry, up to 365 days (set at creation) | Third-party integrations, automation | | **Publishable Token** | No expiration | Client-side embedding (journeys, portals) | -Long-lived Access Tokens inherit the creating user's roles and permissions, and can be revoked at any time. Publishable Tokens are restricted to a narrow set of public-facing operations. See [Access Tokens](/docs/auth/access-tokens) and [Token Types](/docs/auth/token-types) for details. +Access Tokens support an optional expiry, set when the token is created — either in the management UI or via the `expires_in` parameter of the [Access Token API](/api/access-token). Tokens created without an expiry remain valid until revoked; tokens created with one can live up to 365 days and stay listed and revocable until they expire. Access Tokens inherit the creating user's roles and permissions, and can be revoked at any time. Publishable Tokens are restricted to a narrow set of public-facing operations. See [Access Tokens](/docs/auth/access-tokens) and [Token Types](/docs/auth/token-types) for details. ### Authentication Methods @@ -197,7 +197,7 @@ WAF rules are continuously tuned based on traffic patterns and threat intelligen epilot distinguishes between two categories of API credentials: -- **Access Tokens** — Secret, long-lived tokens that carry the creating user's full permissions. Keep confidential; use for server-to-server integrations. See [Access Tokens](/docs/auth/access-tokens). +- **Access Tokens** — Secret tokens that carry the creating user's permissions. Keep confidential; use for server-to-server integrations, and set an expiry at creation to limit exposure. See [Access Tokens](/docs/auth/access-tokens). - **Publishable Tokens** — Safe to embed in client-side code (journey embed scripts, portal widgets). Restricted to public operations and cannot access sensitive data. See [Token Types](/docs/auth/token-types). :::warning @@ -282,6 +282,6 @@ epilot maintains the following certifications and compliance measures: - [Passkeys](/docs/auth/passkeys) -- Phishing-resistant biometric and hardware key authentication - [SSO](/docs/sso/single-sign-on) — Single sign-on with OIDC and SAML identity providers - [Authorization](/docs/auth/authorization) — JWT validation, API Gateway authorizer, Permissions API -- [Access Tokens](/docs/auth/access-tokens) — Creating and managing long-lived API tokens +- [Access Tokens](/docs/auth/access-tokens) — Creating and managing API tokens - [Token Types](/docs/auth/token-types) — Comparison of access tokens vs. publishable tokens - [Permissions](/docs/auth/permissions) — RBAC model, grant evaluation, role management diff --git a/docs/auth/token-types.md b/docs/auth/token-types.md index 3cd2c0ad..ba68d294 100644 --- a/docs/auth/token-types.md +++ b/docs/auth/token-types.md @@ -11,7 +11,7 @@ epilot uses three token types for authentication. Choose the right one for your | | OAuth 2.0 Token | Access Token | Publishable Token | |---|---|---|---| -| **Lifetime** | 60 minutes | Long-lived (no expiry) | Long-lived (no expiry) | +| **Lifetime** | 60 minutes | Configurable expiry, up to 365 days (valid until revoked if unset) | Long-lived (no expiry) | | **Use case** | Interactive user sessions | Server-side API integrations | Client-side public apps (journeys, portals) | | **Format** | JWT (Cognito-issued) | JWT (epilot-issued) | JWT (epilot-issued, public key) | | **Refresh** | Via refresh token | Not needed | Not needed | @@ -35,12 +35,12 @@ On successful authentication, Cognito issues three tokens: OAuth tokens expire after **60 minutes**. Use the refresh token to obtain new tokens transparently. :::tip -OAuth tokens suit interactive user sessions. For API integrations, use long-lived [Access Tokens](/docs/auth/access-tokens) instead. +OAuth tokens suit interactive user sessions. For API integrations, use [Access Tokens](/docs/auth/access-tokens) instead. ::: ## Access Tokens -Access Tokens are long-lived JWTs for server-side integrations — the recommended authentication method for backend systems, scripts, and third-party applications. See [Access Tokens](/docs/auth/access-tokens) for full management details. +Access Tokens are JWTs for server-side integrations — the recommended authentication method for backend systems, scripts, and third-party applications. You can set an expiry when creating a token; tokens created without one stay valid until revoked. See [Access Tokens](/docs/auth/access-tokens) for full management details. ### How They Work @@ -63,6 +63,7 @@ authorize(accessTokenClient, cognitoIdToken); const { data } = await accessTokenClient.createAccessToken(null, { name: 'SAP Integration', assume_roles: ['123:sap_integration_role'], + expires_in: '30d', // optional expiry — seconds or a duration string }); // data.access_token contains the token — save it securely @@ -78,6 +79,17 @@ Scope each Access Token to specific roles via `assume_roles`. If omitted, the to } ``` +### Token Expiry + +Set an optional expiry when creating a token via the `expires_in` parameter — either a number of seconds (e.g. `3600`) or a duration string with time units (e.g. `'10h'`, `'7d'`, `'2 days'`). Expired tokens are rejected by the API Gateway authorizer like any other expired JWT. + +- **Standard Access Tokens** (`token_type: api`, the default) accept an expiry between 30 seconds and **365 days**. +- Other token types created with an explicit `expires_in` (e.g. `app` tokens) are capped at **7 days**, since they're ephemeral and not manageable from the token list. + +If `expires_in` is omitted, the token does not expire and remains valid until revoked. + +Access Tokens created with an expiry are still persisted, listed, and revocable like any other token — the create response includes an `expires_at` timestamp, and the token disappears from the list once it expires. + :::warning Creating access tokens requires the `token:create` permission. The generated token is shown **only once** and cannot be recovered. ::: @@ -139,6 +151,7 @@ All token types use JWT (JSON Web Token) format, signed with RS256. | `assume_roles` | List of role IDs (e.g., `["123:owner"]`) | | `iss` | Access Token service issuer URL | | `iat` | Issued-at timestamp | +| `exp` | Expiration timestamp (present when the token was created with an expiry) | ### Token Verification