diff --git a/.stainless/stainless.yml b/.stainless/stainless.yml index 7345cc18..600cd81e 100644 --- a/.stainless/stainless.yml +++ b/.stainless/stainless.yml @@ -476,9 +476,15 @@ resources: list: endpoint: get /auth/sessions paginated: false + refresh: + endpoint: post /auth/sessions/{id}/refresh + body_param_name: AuthSessionRefreshRequest delete: delete /auth/sessions/{id} models: session_list_response: '#/components/schemas/SessionListResponse' + auth_session_refresh_request: '#/components/schemas/AuthSessionRefreshRequest' + auth_session: '#/components/schemas/AuthSession' + signed_request_challenge: "#/components/schemas/SignedRequestChallenge" agents: methods: diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index bf6fdd7b..a2c5f0dc 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -4437,6 +4437,111 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + /auth/sessions/{id}/refresh: + post: + summary: Refresh an authentication session + description: | + Refresh an active Embedded Wallet auth session and create a new session signing key. Session refresh is a two-step signed-retry flow: + + 1. Call `POST /auth/sessions/{id}/refresh` with the request body `{ "clientPublicKey": "04..." }` and no signature headers. Grid builds a Turnkey create-read-write-session payload, binds the supplied `clientPublicKey` into that payload, persists it as a pending request, and returns `202` with `payloadToSign`, `requestId`, and `expiresAt`. + + 2. Sign `payloadToSign` with the current session signing key, then retry the same request with the full API-key stamp as `Grid-Wallet-Signature`, the `requestId` echoed back as `Request-Id`, and the same `clientPublicKey` in the request body. On success, Grid returns a new `AuthSession` with an `encryptedSessionSigningKey` sealed to that client public key. + + The original session must still be active on both steps so it can authorize the refresh. If the session has already expired, use the credential reauthentication flow instead. + operationId: refreshAuthSession + tags: + - Embedded Wallet Auth + security: + - BasicAuth: [] + parameters: + - name: id + in: path + description: The id of the active session to refresh. + required: true + schema: + type: string + example: Session:019542f5-b3e7-1d02-0000-000000000003 + - name: Grid-Wallet-Signature + in: header + required: false + description: Full API-key stamp built over the prior `payloadToSign` with the current session API keypair. Required on the signed retry; ignored on the initial call. + schema: + type: string + example: eyJwdWJsaWNLZXkiOiIwMmExYjIuLi4iLCJzaWduYXR1cmUiOiIzMDQ1MDIyMTAwLi4uIiwic2NoZW1lIjoiUDI1Nl9FQ0RTQV9TSEEyNTYifQ + - name: Request-Id + in: header + required: false + description: The `requestId` returned in the prior `202` response, echoed back on the signed retry so the server can correlate it with the issued challenge. Required on the signed retry; must be paired with `Grid-Wallet-Signature`. + schema: + type: string + example: Request:019542f5-b3e7-1d02-0000-000000000010 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AuthSessionRefreshRequest' + examples: + refresh: + summary: Refresh an active session + value: + clientPublicKey: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 + responses: + '201': + description: New authentication session created successfully. + content: + application/json: + schema: + $ref: '#/components/schemas/AuthSession' + examples: + session: + summary: Refreshed authentication session + value: + id: Session:019542f5-b3e7-1d02-0000-000000000011 + accountId: InternalAccount:019542f5-b3e7-1d02-0000-000000000002 + type: EMAIL_OTP + encryptedSessionSigningKey: w99a5xV6A75TfoAUkZn869fVyDYvgVsKrawMALZXmrauZd8hEv66EkPU1Z42CUaHESQjcA5bqd8dynTGBMLWB9ewtXWPEVbZvocB4Tw2K1vQVp7uwjf + nickname: example@lightspark.com + createdAt: '2026-04-08T15:30:01Z' + updatedAt: '2026-04-08T15:35:00Z' + expiresAt: '2026-04-08T15:50:00Z' + '202': + description: Challenge issued. The response contains `payloadToSign` plus a `requestId`. Build an API-key stamp over `payloadToSign` with the current session API keypair, then echo `requestId` on the signed retry. + content: + application/json: + schema: + $ref: '#/components/schemas/SignedRequestChallenge' + examples: + challenge: + summary: Session refresh challenge + value: + payloadToSign: '{"type":"ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2","timestampMs":"1746736509954","organizationId":"org_abc123","parameters":{"targetPublicKey":"04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2"}}' + requestId: Request:019542f5-b3e7-1d02-0000-000000000010 + expiresAt: '2026-04-08T15:35:00Z' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized. Returned when the `BasicAuth` credentials are missing or invalid, when the target session is no longer active and cannot be used for refresh, when the signed retry omits `Grid-Wallet-Signature`, when the provided signature is malformed or does not match the pending refresh challenge, when the `Request-Id` does not match an unexpired pending challenge, or when the retry's `clientPublicKey` does not match the one bound into `payloadToSign` on the initial call. + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '404': + description: Session not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error404' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' /agents: post: summary: Create an agent @@ -15510,7 +15615,7 @@ components: - payloadToSign - requestId - expiresAt - description: Common base for two-step signed-retry challenge responses on Embedded Wallet endpoints (credential revocation, session revocation, wallet export, and similar). Holds the signing fields shared across every challenge shape; each variant composes this base via `allOf` and adds its own resource `id` (and `type`, when applicable) with variant-specific description and example. + description: Common base for two-step signed-retry challenge responses on Embedded Wallet endpoints (credential registration or revocation, session refresh or revocation, wallet export, and similar). Holds the signing fields shared across every challenge shape; each variant composes this base via `allOf` and adds its own resource `id` (and `type`, when applicable) with variant-specific description and example. properties: payloadToSign: type: string @@ -15849,7 +15954,7 @@ components: PASSKEY: '#/components/schemas/PasskeyCredentialVerifyRequest' AuthSession: title: Authentication Session - description: An authentication session on an Embedded Wallet internal account. Returned from `GET /auth/sessions` (list) and `POST /auth/credentials/{id}/verify` (on credential verification). Only the verify response includes `encryptedSessionSigningKey` — it is delivered exactly once at the moment the session is issued and is never returned by the list endpoint. + description: An authentication session on an Embedded Wallet internal account. Returned from `GET /auth/sessions` (list) and `POST /auth/credentials/{id}/verify` (on credential verification) or `POST /auth/sessions/{id}/refresh` (on mid-session refresh). Only session-issuing responses include `encryptedSessionSigningKey` — it is delivered exactly once at the moment the session is issued and is never returned by the list endpoint. allOf: - $ref: '#/components/schemas/AuthMethod' - type: object @@ -15864,9 +15969,9 @@ components: encryptedSessionSigningKey: type: string description: |- - HPKE-encrypted session signing key, sealed to the `clientPublicKey` supplied on the verify request. Encoded as a base58check string: the decoded payload is a 33-byte compressed P-256 encapsulated public key followed by AES-256-GCM ciphertext. The client decrypts this key with its private key and uses it to sign subsequent Embedded Wallet requests until `expiresAt`. + HPKE-encrypted session signing key, sealed to the `clientPublicKey` supplied on the verification or refresh request. Encoded as a base58check string: the decoded payload is a 33-byte compressed P-256 encapsulated public key followed by AES-256-GCM ciphertext. The client decrypts this key with its private key and uses it to sign subsequent Embedded Wallet requests until `expiresAt`. - Only returned from `POST /auth/credentials/{id}/verify` (where the session is first issued). Omitted from responses that simply surface existing sessions (e.g. `GET /auth/sessions`) — Grid does not retain the plaintext key after the client has decrypted it. + Only returned from session-issuing responses like `POST /auth/credentials/{id}/verify` and `POST /auth/sessions/{id}/refresh`. Omitted from responses that simply surface existing sessions (e.g. `GET /auth/sessions`) — Grid does not retain the plaintext key after the client has decrypted it. example: w99a5xV6A75TfoAUkZn869fVyDYvgVsKrawMALZXmrauZd8hEv66EkPU1Z42CUaHESQjcA5bqd8dynTGBMLWB9ewtXWPEVbZvocB4Tw2K1vQVp7uwjf expiresAt: type: string @@ -15962,6 +16067,18 @@ components: description: List of active authentication sessions for the internal account. items: $ref: '#/components/schemas/AuthSession' + AuthSessionRefreshRequest: + title: Auth Session Refresh Request + description: Request body for refreshing an active authentication session. The `clientPublicKey` is required on both steps of the signed-retry flow. On the initial call, Grid binds this key into the Turnkey session-creation payload returned as `payloadToSign`; on the signed retry, the client echoes the same key back and Grid uses it to encrypt the newly issued session signing key. + type: object + required: + - clientPublicKey + properties: + clientPublicKey: + type: string + pattern: ^04[0-9a-fA-F]{128}$ + description: Client-generated P-256 public key, hex-encoded in uncompressed SEC1 format (`04` prefix followed by the 32-byte X and 32-byte Y coordinates; 130 hex characters total). The matching private key must remain on the client. Grid binds this key into the session-creation payload on the initial call and seals the returned `encryptedSessionSigningKey` to it on the signed retry. + example: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 AgentPermission: type: string enum: diff --git a/openapi.yaml b/openapi.yaml index bf6fdd7b..a2c5f0dc 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -4437,6 +4437,111 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + /auth/sessions/{id}/refresh: + post: + summary: Refresh an authentication session + description: | + Refresh an active Embedded Wallet auth session and create a new session signing key. Session refresh is a two-step signed-retry flow: + + 1. Call `POST /auth/sessions/{id}/refresh` with the request body `{ "clientPublicKey": "04..." }` and no signature headers. Grid builds a Turnkey create-read-write-session payload, binds the supplied `clientPublicKey` into that payload, persists it as a pending request, and returns `202` with `payloadToSign`, `requestId`, and `expiresAt`. + + 2. Sign `payloadToSign` with the current session signing key, then retry the same request with the full API-key stamp as `Grid-Wallet-Signature`, the `requestId` echoed back as `Request-Id`, and the same `clientPublicKey` in the request body. On success, Grid returns a new `AuthSession` with an `encryptedSessionSigningKey` sealed to that client public key. + + The original session must still be active on both steps so it can authorize the refresh. If the session has already expired, use the credential reauthentication flow instead. + operationId: refreshAuthSession + tags: + - Embedded Wallet Auth + security: + - BasicAuth: [] + parameters: + - name: id + in: path + description: The id of the active session to refresh. + required: true + schema: + type: string + example: Session:019542f5-b3e7-1d02-0000-000000000003 + - name: Grid-Wallet-Signature + in: header + required: false + description: Full API-key stamp built over the prior `payloadToSign` with the current session API keypair. Required on the signed retry; ignored on the initial call. + schema: + type: string + example: eyJwdWJsaWNLZXkiOiIwMmExYjIuLi4iLCJzaWduYXR1cmUiOiIzMDQ1MDIyMTAwLi4uIiwic2NoZW1lIjoiUDI1Nl9FQ0RTQV9TSEEyNTYifQ + - name: Request-Id + in: header + required: false + description: The `requestId` returned in the prior `202` response, echoed back on the signed retry so the server can correlate it with the issued challenge. Required on the signed retry; must be paired with `Grid-Wallet-Signature`. + schema: + type: string + example: Request:019542f5-b3e7-1d02-0000-000000000010 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AuthSessionRefreshRequest' + examples: + refresh: + summary: Refresh an active session + value: + clientPublicKey: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 + responses: + '201': + description: New authentication session created successfully. + content: + application/json: + schema: + $ref: '#/components/schemas/AuthSession' + examples: + session: + summary: Refreshed authentication session + value: + id: Session:019542f5-b3e7-1d02-0000-000000000011 + accountId: InternalAccount:019542f5-b3e7-1d02-0000-000000000002 + type: EMAIL_OTP + encryptedSessionSigningKey: w99a5xV6A75TfoAUkZn869fVyDYvgVsKrawMALZXmrauZd8hEv66EkPU1Z42CUaHESQjcA5bqd8dynTGBMLWB9ewtXWPEVbZvocB4Tw2K1vQVp7uwjf + nickname: example@lightspark.com + createdAt: '2026-04-08T15:30:01Z' + updatedAt: '2026-04-08T15:35:00Z' + expiresAt: '2026-04-08T15:50:00Z' + '202': + description: Challenge issued. The response contains `payloadToSign` plus a `requestId`. Build an API-key stamp over `payloadToSign` with the current session API keypair, then echo `requestId` on the signed retry. + content: + application/json: + schema: + $ref: '#/components/schemas/SignedRequestChallenge' + examples: + challenge: + summary: Session refresh challenge + value: + payloadToSign: '{"type":"ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2","timestampMs":"1746736509954","organizationId":"org_abc123","parameters":{"targetPublicKey":"04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2"}}' + requestId: Request:019542f5-b3e7-1d02-0000-000000000010 + expiresAt: '2026-04-08T15:35:00Z' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized. Returned when the `BasicAuth` credentials are missing or invalid, when the target session is no longer active and cannot be used for refresh, when the signed retry omits `Grid-Wallet-Signature`, when the provided signature is malformed or does not match the pending refresh challenge, when the `Request-Id` does not match an unexpired pending challenge, or when the retry's `clientPublicKey` does not match the one bound into `payloadToSign` on the initial call. + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '404': + description: Session not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error404' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' /agents: post: summary: Create an agent @@ -15510,7 +15615,7 @@ components: - payloadToSign - requestId - expiresAt - description: Common base for two-step signed-retry challenge responses on Embedded Wallet endpoints (credential revocation, session revocation, wallet export, and similar). Holds the signing fields shared across every challenge shape; each variant composes this base via `allOf` and adds its own resource `id` (and `type`, when applicable) with variant-specific description and example. + description: Common base for two-step signed-retry challenge responses on Embedded Wallet endpoints (credential registration or revocation, session refresh or revocation, wallet export, and similar). Holds the signing fields shared across every challenge shape; each variant composes this base via `allOf` and adds its own resource `id` (and `type`, when applicable) with variant-specific description and example. properties: payloadToSign: type: string @@ -15849,7 +15954,7 @@ components: PASSKEY: '#/components/schemas/PasskeyCredentialVerifyRequest' AuthSession: title: Authentication Session - description: An authentication session on an Embedded Wallet internal account. Returned from `GET /auth/sessions` (list) and `POST /auth/credentials/{id}/verify` (on credential verification). Only the verify response includes `encryptedSessionSigningKey` — it is delivered exactly once at the moment the session is issued and is never returned by the list endpoint. + description: An authentication session on an Embedded Wallet internal account. Returned from `GET /auth/sessions` (list) and `POST /auth/credentials/{id}/verify` (on credential verification) or `POST /auth/sessions/{id}/refresh` (on mid-session refresh). Only session-issuing responses include `encryptedSessionSigningKey` — it is delivered exactly once at the moment the session is issued and is never returned by the list endpoint. allOf: - $ref: '#/components/schemas/AuthMethod' - type: object @@ -15864,9 +15969,9 @@ components: encryptedSessionSigningKey: type: string description: |- - HPKE-encrypted session signing key, sealed to the `clientPublicKey` supplied on the verify request. Encoded as a base58check string: the decoded payload is a 33-byte compressed P-256 encapsulated public key followed by AES-256-GCM ciphertext. The client decrypts this key with its private key and uses it to sign subsequent Embedded Wallet requests until `expiresAt`. + HPKE-encrypted session signing key, sealed to the `clientPublicKey` supplied on the verification or refresh request. Encoded as a base58check string: the decoded payload is a 33-byte compressed P-256 encapsulated public key followed by AES-256-GCM ciphertext. The client decrypts this key with its private key and uses it to sign subsequent Embedded Wallet requests until `expiresAt`. - Only returned from `POST /auth/credentials/{id}/verify` (where the session is first issued). Omitted from responses that simply surface existing sessions (e.g. `GET /auth/sessions`) — Grid does not retain the plaintext key after the client has decrypted it. + Only returned from session-issuing responses like `POST /auth/credentials/{id}/verify` and `POST /auth/sessions/{id}/refresh`. Omitted from responses that simply surface existing sessions (e.g. `GET /auth/sessions`) — Grid does not retain the plaintext key after the client has decrypted it. example: w99a5xV6A75TfoAUkZn869fVyDYvgVsKrawMALZXmrauZd8hEv66EkPU1Z42CUaHESQjcA5bqd8dynTGBMLWB9ewtXWPEVbZvocB4Tw2K1vQVp7uwjf expiresAt: type: string @@ -15962,6 +16067,18 @@ components: description: List of active authentication sessions for the internal account. items: $ref: '#/components/schemas/AuthSession' + AuthSessionRefreshRequest: + title: Auth Session Refresh Request + description: Request body for refreshing an active authentication session. The `clientPublicKey` is required on both steps of the signed-retry flow. On the initial call, Grid binds this key into the Turnkey session-creation payload returned as `payloadToSign`; on the signed retry, the client echoes the same key back and Grid uses it to encrypt the newly issued session signing key. + type: object + required: + - clientPublicKey + properties: + clientPublicKey: + type: string + pattern: ^04[0-9a-fA-F]{128}$ + description: Client-generated P-256 public key, hex-encoded in uncompressed SEC1 format (`04` prefix followed by the 32-byte X and 32-byte Y coordinates; 130 hex characters total). The matching private key must remain on the client. Grid binds this key into the session-creation payload on the initial call and seals the returned `encryptedSessionSigningKey` to it on the signed retry. + example: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 AgentPermission: type: string enum: diff --git a/openapi/components/schemas/auth/AuthSession.yaml b/openapi/components/schemas/auth/AuthSession.yaml index 9c58bb75..4781efc4 100644 --- a/openapi/components/schemas/auth/AuthSession.yaml +++ b/openapi/components/schemas/auth/AuthSession.yaml @@ -2,10 +2,11 @@ title: Authentication Session description: >- An authentication session on an Embedded Wallet internal account. Returned from `GET /auth/sessions` (list) and - `POST /auth/credentials/{id}/verify` (on credential verification). - Only the verify response includes `encryptedSessionSigningKey` — it - is delivered exactly once at the moment the session is issued and - is never returned by the list endpoint. + `POST /auth/credentials/{id}/verify` (on credential verification) or + `POST /auth/sessions/{id}/refresh` (on mid-session refresh). + Only session-issuing responses include `encryptedSessionSigningKey` — + it is delivered exactly once at the moment the session is issued and is + never returned by the list endpoint. allOf: - $ref: ./AuthMethod.yaml - type: object @@ -26,7 +27,8 @@ allOf: type: string description: >- HPKE-encrypted session signing key, sealed to the - `clientPublicKey` supplied on the verify request. Encoded as + `clientPublicKey` supplied on the verification or refresh request. + Encoded as a base58check string: the decoded payload is a 33-byte compressed P-256 encapsulated public key followed by AES-256-GCM ciphertext. The client decrypts this key with @@ -34,11 +36,12 @@ allOf: Wallet requests until `expiresAt`. - Only returned from `POST /auth/credentials/{id}/verify` - (where the session is first issued). Omitted from responses - that simply surface existing sessions (e.g. - `GET /auth/sessions`) — Grid does not retain the plaintext - key after the client has decrypted it. + Only returned from session-issuing responses like + `POST /auth/credentials/{id}/verify` and + `POST /auth/sessions/{id}/refresh`. Omitted from responses that + simply surface existing sessions (e.g. `GET /auth/sessions`) — + Grid does not retain the plaintext key after the client has + decrypted it. example: w99a5xV6A75TfoAUkZn869fVyDYvgVsKrawMALZXmrauZd8hEv66EkPU1Z42CUaHESQjcA5bqd8dynTGBMLWB9ewtXWPEVbZvocB4Tw2K1vQVp7uwjf expiresAt: type: string diff --git a/openapi/components/schemas/auth/AuthSessionRefreshRequest.yaml b/openapi/components/schemas/auth/AuthSessionRefreshRequest.yaml new file mode 100644 index 00000000..d8f71107 --- /dev/null +++ b/openapi/components/schemas/auth/AuthSessionRefreshRequest.yaml @@ -0,0 +1,22 @@ +title: Auth Session Refresh Request +description: >- + Request body for refreshing an active authentication session. The + `clientPublicKey` is required on both steps of the signed-retry flow. On the + initial call, Grid binds this key into the Turnkey session-creation payload + returned as `payloadToSign`; on the signed retry, the client echoes the same + key back and Grid uses it to encrypt the newly issued session signing key. +type: object +required: + - clientPublicKey +properties: + clientPublicKey: + type: string + pattern: "^04[0-9a-fA-F]{128}$" + description: >- + Client-generated P-256 public key, hex-encoded in uncompressed SEC1 + format (`04` prefix followed by the 32-byte X and 32-byte Y coordinates; + 130 hex characters total). The matching private key must remain on the + client. Grid binds this key into the session-creation payload on the + initial call and seals the returned `encryptedSessionSigningKey` to it on + the signed retry. + example: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 diff --git a/openapi/components/schemas/common/SignedRequestChallenge.yaml b/openapi/components/schemas/common/SignedRequestChallenge.yaml index d5b22268..f0bd054e 100644 --- a/openapi/components/schemas/common/SignedRequestChallenge.yaml +++ b/openapi/components/schemas/common/SignedRequestChallenge.yaml @@ -6,8 +6,9 @@ required: - expiresAt description: >- Common base for two-step signed-retry challenge responses on - Embedded Wallet endpoints (credential revocation, session revocation, - wallet export, and similar). Holds the signing fields shared across + Embedded Wallet endpoints (credential registration or revocation, + session refresh or revocation, wallet export, and similar). Holds the + signing fields shared across every challenge shape; each variant composes this base via `allOf` and adds its own resource `id` (and `type`, when applicable) with variant-specific description and example. diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 771b4131..65958246 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -213,6 +213,8 @@ paths: $ref: paths/auth/auth_sessions.yaml /auth/sessions/{id}: $ref: paths/auth/auth_sessions_{id}.yaml + /auth/sessions/{id}/refresh: + $ref: paths/auth/auth_sessions_{id}_refresh.yaml /agents: $ref: paths/agents/agents.yaml /agents/approvals: diff --git a/openapi/paths/auth/auth_sessions_{id}_refresh.yaml b/openapi/paths/auth/auth_sessions_{id}_refresh.yaml new file mode 100644 index 00000000..cf4f4d44 --- /dev/null +++ b/openapi/paths/auth/auth_sessions_{id}_refresh.yaml @@ -0,0 +1,136 @@ +post: + summary: Refresh an authentication session + description: > + Refresh an active Embedded Wallet auth session and create a new session + signing key. Session refresh is a two-step signed-retry flow: + + + 1. Call `POST /auth/sessions/{id}/refresh` with the request body + `{ "clientPublicKey": "04..." }` and no signature headers. Grid builds a + Turnkey create-read-write-session payload, binds the supplied + `clientPublicKey` into that payload, persists it as a pending request, and + returns `202` with `payloadToSign`, `requestId`, and `expiresAt`. + + + 2. Sign `payloadToSign` with the current session signing key, then retry the + same request with the full API-key stamp as `Grid-Wallet-Signature`, the + `requestId` echoed back as `Request-Id`, and the same `clientPublicKey` in + the request body. On success, Grid returns a new `AuthSession` with an + `encryptedSessionSigningKey` sealed to that client public key. + + + The original session must still be active on both steps so it can authorize + the refresh. If the session has already expired, use the credential + reauthentication flow instead. + operationId: refreshAuthSession + tags: + - Embedded Wallet Auth + security: + - BasicAuth: [] + parameters: + - name: id + in: path + description: The id of the active session to refresh. + required: true + schema: + type: string + example: Session:019542f5-b3e7-1d02-0000-000000000003 + - name: Grid-Wallet-Signature + in: header + required: false + description: >- + Full API-key stamp built over the prior `payloadToSign` with the current + session API keypair. Required on the signed retry; ignored on the + initial call. + schema: + type: string + example: eyJwdWJsaWNLZXkiOiIwMmExYjIuLi4iLCJzaWduYXR1cmUiOiIzMDQ1MDIyMTAwLi4uIiwic2NoZW1lIjoiUDI1Nl9FQ0RTQV9TSEEyNTYifQ + - name: Request-Id + in: header + required: false + description: >- + The `requestId` returned in the prior `202` response, echoed back on the + signed retry so the server can correlate it with the issued challenge. + Required on the signed retry; must be paired with + `Grid-Wallet-Signature`. + schema: + type: string + example: Request:019542f5-b3e7-1d02-0000-000000000010 + requestBody: + required: true + content: + application/json: + schema: + $ref: ../../components/schemas/auth/AuthSessionRefreshRequest.yaml + examples: + refresh: + summary: Refresh an active session + value: + clientPublicKey: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 + responses: + '201': + description: New authentication session created successfully. + content: + application/json: + schema: + $ref: ../../components/schemas/auth/AuthSession.yaml + examples: + session: + summary: Refreshed authentication session + value: + id: Session:019542f5-b3e7-1d02-0000-000000000011 + accountId: InternalAccount:019542f5-b3e7-1d02-0000-000000000002 + type: EMAIL_OTP + encryptedSessionSigningKey: w99a5xV6A75TfoAUkZn869fVyDYvgVsKrawMALZXmrauZd8hEv66EkPU1Z42CUaHESQjcA5bqd8dynTGBMLWB9ewtXWPEVbZvocB4Tw2K1vQVp7uwjf + nickname: example@lightspark.com + createdAt: '2026-04-08T15:30:01Z' + updatedAt: '2026-04-08T15:35:00Z' + expiresAt: '2026-04-08T15:50:00Z' + '202': + description: >- + Challenge issued. The response contains `payloadToSign` plus a + `requestId`. Build an API-key stamp over `payloadToSign` with the + current session API keypair, then echo `requestId` on the signed retry. + content: + application/json: + schema: + $ref: ../../components/schemas/common/SignedRequestChallenge.yaml + examples: + challenge: + summary: Session refresh challenge + value: + payloadToSign: '{"type":"ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2","timestampMs":"1746736509954","organizationId":"org_abc123","parameters":{"targetPublicKey":"04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2"}}' + requestId: Request:019542f5-b3e7-1d02-0000-000000000010 + expiresAt: '2026-04-08T15:35:00Z' + '400': + description: Bad request + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error400.yaml + '401': + description: >- + Unauthorized. Returned when the `BasicAuth` credentials are missing or + invalid, when the target session is no longer active and cannot be used + for refresh, when the signed retry omits `Grid-Wallet-Signature`, when + the provided signature is malformed or does not match the pending + refresh challenge, when the `Request-Id` does not match an unexpired + pending challenge, or when the retry's `clientPublicKey` does not match + the one bound into + `payloadToSign` on the initial call. + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error401.yaml + '404': + description: Session not found + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error404.yaml + '500': + description: Internal service error + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error500.yaml