From f4789cb1459fcbfc0e4fa7c742c3fbb7fb0a328b Mon Sep 17 00:00:00 2001 From: Dhruv Pareek Date: Thu, 7 May 2026 17:42:23 -0700 Subject: [PATCH] Add auth session refresh endpoints --- .stainless/stainless.yml | 9 + mintlify/openapi.yaml | 179 +++++++++++++++++- openapi.yaml | 179 +++++++++++++++++- .../components/schemas/auth/AuthSession.yaml | 14 +- .../auth/AuthSessionReauthRequest.yaml | 24 +++ openapi/openapi.yaml | 4 + .../auth/auth_sessions_{id}_challenge.yaml | 85 +++++++++ .../paths/auth/auth_sessions_{id}_verify.yaml | 108 +++++++++++ 8 files changed, 592 insertions(+), 10 deletions(-) create mode 100644 openapi/components/schemas/auth/AuthSessionReauthRequest.yaml create mode 100644 openapi/paths/auth/auth_sessions_{id}_challenge.yaml create mode 100644 openapi/paths/auth/auth_sessions_{id}_verify.yaml diff --git a/.stainless/stainless.yml b/.stainless/stainless.yml index 2899b9c3..95e3f866 100644 --- a/.stainless/stainless.yml +++ b/.stainless/stainless.yml @@ -475,9 +475,18 @@ resources: list: endpoint: get /auth/sessions paginated: false + challenge: + endpoint: post /auth/sessions/{id}/challenge + body_param_name: AuthSessionReauthRequest + verify: + endpoint: post /auth/sessions/{id}/verify + body_param_name: AuthSessionReauthRequest delete: delete /auth/sessions/{id} models: session_list_response: '#/components/schemas/SessionListResponse' + auth_session_reauth_request: '#/components/schemas/AuthSessionReauthRequest' + auth_session: '#/components/schemas/AuthSession' + signed_request_challenge: "#/components/schemas/SignedRequestChallenge" agents: methods: diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index a510bc53..20d7ff40 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -4420,6 +4420,167 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + /auth/sessions/{id}/challenge: + post: + summary: Issue a session reauthentication challenge + description: | + Start mid-session reauthentication for an active Embedded Wallet auth session. + + Use this endpoint when a session is still active but close to expiry and the customer wants to extend access without re-running the underlying credential-specific authentication flow. Grid builds a Turnkey create-read-write-session payload, binds the supplied `clientPublicKey` into that payload, persists it as a pending request, and returns the canonical body as `payloadToSign`. + + The client signs `payloadToSign` with the current session signing key, then calls `POST /auth/sessions/{id}/verify` with `Grid-Wallet-Signature`, `Request-Id`, and the same `clientPublicKey`. If the original session has already expired, use the credential reauthentication flow instead. + operationId: challengeAuthSession + tags: + - Embedded Wallet Auth + security: + - BasicAuth: [] + parameters: + - name: id + in: path + description: The id of the active session to reauthenticate. + required: true + schema: + type: string + example: Session:019542f5-b3e7-1d02-0000-000000000003 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AuthSessionReauthRequest' + examples: + reauth: + summary: Start mid-session reauthentication + value: + clientPublicKey: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 + responses: + '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 `POST /auth/sessions/{id}/verify`. + content: + application/json: + schema: + $ref: '#/components/schemas/SignedRequestChallenge' + examples: + challenge: + summary: Session reauthentication 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 + 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' + /auth/sessions/{id}/verify: + post: + summary: Verify a session reauthentication challenge + description: | + Complete mid-session reauthentication for an active Embedded Wallet auth session and create a new session signing key. + + This is the signed retry for `POST /auth/sessions/{id}/challenge`. The request must include the full API-key stamp over the prior `payloadToSign` as `Grid-Wallet-Signature`, the challenge `requestId` as `Request-Id`, and the same `clientPublicKey` that was supplied on the challenge step. On success, Grid returns a new `AuthSession` with an `encryptedSessionSigningKey` sealed to that client public key. + + This endpoint requires the original session to still be active so it can authorize the refresh. If the session has already expired, use the credential reauthentication flow instead. + operationId: verifyAuthSession + tags: + - Embedded Wallet Auth + security: + - BasicAuth: [] + parameters: + - name: id + in: path + description: The id of the active session being reauthenticated. + required: true + schema: + type: string + example: Session:019542f5-b3e7-1d02-0000-000000000003 + - name: Grid-Wallet-Signature + in: header + required: true + description: Full API-key stamp built over the prior `payloadToSign` with the current session API keypair. + schema: + type: string + example: eyJwdWJsaWNLZXkiOiIwMmExYjIuLi4iLCJzaWduYXR1cmUiOiIzMDQ1MDIyMTAwLi4uIiwic2NoZW1lIjoiUDI1Nl9FQ0RTQV9TSEEyNTYifQ + - name: Request-Id + in: header + required: true + description: The `requestId` returned in the prior challenge response, echoed back so the server can correlate this signed retry with the issued challenge. + schema: + type: string + example: Request:019542f5-b3e7-1d02-0000-000000000010 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AuthSessionReauthRequest' + examples: + reauth: + summary: Complete mid-session reauthentication + 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' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized. Returned when the provided `Grid-Wallet-Signature` is missing, malformed, or does not match the pending reauthentication 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 challenge step. + 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 @@ -15882,7 +16043,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}/verify` (on mid-session reauthentication). 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. allOf: - $ref: '#/components/schemas/AuthMethod' - type: object @@ -15899,7 +16060,7 @@ components: 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`. - 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}/verify`. 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 @@ -15990,6 +16151,20 @@ components: description: List of active authentication sessions for the internal account. items: $ref: '#/components/schemas/AuthSession' + AuthSessionReauthRequest: + title: Auth Session Reauthentication Request + description: Request body for mid-session reauthentication. The `clientPublicKey` is required on both steps of the signed-retry flow. On the challenge step, Grid binds this key into the Turnkey session-creation payload returned as `payloadToSign`; on the verify step, 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}$ + minLength: 130 + maxLength: 130 + 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 challenge step and seals the returned `encryptedSessionSigningKey` to it on the verify step. + example: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 AgentPermission: type: string enum: diff --git a/openapi.yaml b/openapi.yaml index a510bc53..20d7ff40 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -4420,6 +4420,167 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + /auth/sessions/{id}/challenge: + post: + summary: Issue a session reauthentication challenge + description: | + Start mid-session reauthentication for an active Embedded Wallet auth session. + + Use this endpoint when a session is still active but close to expiry and the customer wants to extend access without re-running the underlying credential-specific authentication flow. Grid builds a Turnkey create-read-write-session payload, binds the supplied `clientPublicKey` into that payload, persists it as a pending request, and returns the canonical body as `payloadToSign`. + + The client signs `payloadToSign` with the current session signing key, then calls `POST /auth/sessions/{id}/verify` with `Grid-Wallet-Signature`, `Request-Id`, and the same `clientPublicKey`. If the original session has already expired, use the credential reauthentication flow instead. + operationId: challengeAuthSession + tags: + - Embedded Wallet Auth + security: + - BasicAuth: [] + parameters: + - name: id + in: path + description: The id of the active session to reauthenticate. + required: true + schema: + type: string + example: Session:019542f5-b3e7-1d02-0000-000000000003 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AuthSessionReauthRequest' + examples: + reauth: + summary: Start mid-session reauthentication + value: + clientPublicKey: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 + responses: + '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 `POST /auth/sessions/{id}/verify`. + content: + application/json: + schema: + $ref: '#/components/schemas/SignedRequestChallenge' + examples: + challenge: + summary: Session reauthentication 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 + 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' + /auth/sessions/{id}/verify: + post: + summary: Verify a session reauthentication challenge + description: | + Complete mid-session reauthentication for an active Embedded Wallet auth session and create a new session signing key. + + This is the signed retry for `POST /auth/sessions/{id}/challenge`. The request must include the full API-key stamp over the prior `payloadToSign` as `Grid-Wallet-Signature`, the challenge `requestId` as `Request-Id`, and the same `clientPublicKey` that was supplied on the challenge step. On success, Grid returns a new `AuthSession` with an `encryptedSessionSigningKey` sealed to that client public key. + + This endpoint requires the original session to still be active so it can authorize the refresh. If the session has already expired, use the credential reauthentication flow instead. + operationId: verifyAuthSession + tags: + - Embedded Wallet Auth + security: + - BasicAuth: [] + parameters: + - name: id + in: path + description: The id of the active session being reauthenticated. + required: true + schema: + type: string + example: Session:019542f5-b3e7-1d02-0000-000000000003 + - name: Grid-Wallet-Signature + in: header + required: true + description: Full API-key stamp built over the prior `payloadToSign` with the current session API keypair. + schema: + type: string + example: eyJwdWJsaWNLZXkiOiIwMmExYjIuLi4iLCJzaWduYXR1cmUiOiIzMDQ1MDIyMTAwLi4uIiwic2NoZW1lIjoiUDI1Nl9FQ0RTQV9TSEEyNTYifQ + - name: Request-Id + in: header + required: true + description: The `requestId` returned in the prior challenge response, echoed back so the server can correlate this signed retry with the issued challenge. + schema: + type: string + example: Request:019542f5-b3e7-1d02-0000-000000000010 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AuthSessionReauthRequest' + examples: + reauth: + summary: Complete mid-session reauthentication + 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' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized. Returned when the provided `Grid-Wallet-Signature` is missing, malformed, or does not match the pending reauthentication 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 challenge step. + 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 @@ -15882,7 +16043,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}/verify` (on mid-session reauthentication). 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. allOf: - $ref: '#/components/schemas/AuthMethod' - type: object @@ -15899,7 +16060,7 @@ components: 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`. - 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}/verify`. 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 @@ -15990,6 +16151,20 @@ components: description: List of active authentication sessions for the internal account. items: $ref: '#/components/schemas/AuthSession' + AuthSessionReauthRequest: + title: Auth Session Reauthentication Request + description: Request body for mid-session reauthentication. The `clientPublicKey` is required on both steps of the signed-retry flow. On the challenge step, Grid binds this key into the Turnkey session-creation payload returned as `payloadToSign`; on the verify step, 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}$ + minLength: 130 + maxLength: 130 + 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 challenge step and seals the returned `encryptedSessionSigningKey` to it on the verify step. + example: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 AgentPermission: type: string enum: diff --git a/openapi/components/schemas/auth/AuthSession.yaml b/openapi/components/schemas/auth/AuthSession.yaml index 9c58bb75..061f545c 100644 --- a/openapi/components/schemas/auth/AuthSession.yaml +++ b/openapi/components/schemas/auth/AuthSession.yaml @@ -2,7 +2,8 @@ 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). + `POST /auth/credentials/{id}/verify` (on credential verification) or + `POST /auth/sessions/{id}/verify` (on mid-session reauthentication). 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. @@ -34,11 +35,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}/verify`. 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/AuthSessionReauthRequest.yaml b/openapi/components/schemas/auth/AuthSessionReauthRequest.yaml new file mode 100644 index 00000000..65e7abd4 --- /dev/null +++ b/openapi/components/schemas/auth/AuthSessionReauthRequest.yaml @@ -0,0 +1,24 @@ +title: Auth Session Reauthentication Request +description: >- + Request body for mid-session reauthentication. The `clientPublicKey` is + required on both steps of the signed-retry flow. On the challenge step, Grid + binds this key into the Turnkey session-creation payload returned as + `payloadToSign`; on the verify step, 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}$" + minLength: 130 + maxLength: 130 + 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 + challenge step and seals the returned `encryptedSessionSigningKey` to it + on the verify step. + example: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index d2ae90bf..cee1ebf0 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -215,6 +215,10 @@ paths: $ref: paths/auth/auth_sessions.yaml /auth/sessions/{id}: $ref: paths/auth/auth_sessions_{id}.yaml + /auth/sessions/{id}/challenge: + $ref: paths/auth/auth_sessions_{id}_challenge.yaml + /auth/sessions/{id}/verify: + $ref: paths/auth/auth_sessions_{id}_verify.yaml /agents: $ref: paths/agents/agents.yaml /agents/approvals: diff --git a/openapi/paths/auth/auth_sessions_{id}_challenge.yaml b/openapi/paths/auth/auth_sessions_{id}_challenge.yaml new file mode 100644 index 00000000..dd313d2e --- /dev/null +++ b/openapi/paths/auth/auth_sessions_{id}_challenge.yaml @@ -0,0 +1,85 @@ +post: + summary: Issue a session reauthentication challenge + description: > + Start mid-session reauthentication for an active Embedded Wallet auth + session. + + + Use this endpoint when a session is still active but close to expiry and + the customer wants to extend access without re-running the underlying + credential-specific authentication flow. Grid builds a Turnkey + create-read-write-session payload, binds the supplied `clientPublicKey` into + that payload, persists it as a pending request, and returns the canonical + body as `payloadToSign`. + + + The client signs `payloadToSign` with the current session signing key, then + calls `POST /auth/sessions/{id}/verify` with `Grid-Wallet-Signature`, + `Request-Id`, and the same `clientPublicKey`. If the original session has + already expired, use the credential reauthentication flow instead. + operationId: challengeAuthSession + tags: + - Embedded Wallet Auth + security: + - BasicAuth: [] + parameters: + - name: id + in: path + description: The id of the active session to reauthenticate. + required: true + schema: + type: string + example: Session:019542f5-b3e7-1d02-0000-000000000003 + requestBody: + required: true + content: + application/json: + schema: + $ref: ../../components/schemas/auth/AuthSessionReauthRequest.yaml + examples: + reauth: + summary: Start mid-session reauthentication + value: + clientPublicKey: 04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2 + responses: + '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 + `POST /auth/sessions/{id}/verify`. + content: + application/json: + schema: + $ref: ../../components/schemas/common/SignedRequestChallenge.yaml + examples: + challenge: + summary: Session reauthentication 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 + 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 diff --git a/openapi/paths/auth/auth_sessions_{id}_verify.yaml b/openapi/paths/auth/auth_sessions_{id}_verify.yaml new file mode 100644 index 00000000..9d0a3d16 --- /dev/null +++ b/openapi/paths/auth/auth_sessions_{id}_verify.yaml @@ -0,0 +1,108 @@ +post: + summary: Verify a session reauthentication challenge + description: > + Complete mid-session reauthentication for an active Embedded Wallet auth + session and create a new session signing key. + + + This is the signed retry for `POST /auth/sessions/{id}/challenge`. The + request must include the full API-key stamp over the prior `payloadToSign` + as `Grid-Wallet-Signature`, the challenge `requestId` as `Request-Id`, and + the same `clientPublicKey` that was supplied on the challenge step. On + success, Grid returns a new `AuthSession` with an + `encryptedSessionSigningKey` sealed to that client public key. + + + This endpoint requires the original session to still be active so it can + authorize the refresh. If the session has already expired, use the + credential reauthentication flow instead. + operationId: verifyAuthSession + tags: + - Embedded Wallet Auth + security: + - BasicAuth: [] + parameters: + - name: id + in: path + description: The id of the active session being reauthenticated. + required: true + schema: + type: string + example: Session:019542f5-b3e7-1d02-0000-000000000003 + - name: Grid-Wallet-Signature + in: header + required: true + description: >- + Full API-key stamp built over the prior `payloadToSign` with the current + session API keypair. + schema: + type: string + example: eyJwdWJsaWNLZXkiOiIwMmExYjIuLi4iLCJzaWduYXR1cmUiOiIzMDQ1MDIyMTAwLi4uIiwic2NoZW1lIjoiUDI1Nl9FQ0RTQV9TSEEyNTYifQ + - name: Request-Id + in: header + required: true + description: >- + The `requestId` returned in the prior challenge response, echoed back so + the server can correlate this signed retry with the issued challenge. + schema: + type: string + example: Request:019542f5-b3e7-1d02-0000-000000000010 + requestBody: + required: true + content: + application/json: + schema: + $ref: ../../components/schemas/auth/AuthSessionReauthRequest.yaml + examples: + reauth: + summary: Complete mid-session reauthentication + 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' + '400': + description: Bad request + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error400.yaml + '401': + description: >- + Unauthorized. Returned when the provided `Grid-Wallet-Signature` is + missing, malformed, or does not match the pending reauthentication + 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 challenge step. + 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