diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index e2b98ad11..1e90eb416 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -5968,6 +5968,12 @@ paths: - internal - hybrid responses: + '200': + description: 'An additional-credential setup leg''s underlying wallet-provider activity is still in flight — a `WalletOperationProcessing` body with `status: "PROCESSING"`. The client re-sends the byte-identical stamped retry (same `Request-Id`) until the credential is added; the backend also reconciles the activity to terminal on its own.' + content: + application/json: + schema: + $ref: '#/components/schemas/WalletOperationProcessing' '201': description: Authentication credential created successfully. The body is the created `AuthMethod`. For `EMAIL_OTP`, the nickname is the customer email tied to the internal account; for `SMS_OTP`, it is the customer phone number. OTP responses that trigger a secure OTP challenge carry `otpEncryptionTargetBundle` — the HPKE target bundle the client uses to encrypt the OTP attempt on the subsequent `POST /auth/credentials/{id}/verify`. First-time EMAIL_OTP wallet bootstrap responses may omit that bundle; if it is absent, call `POST /auth/credentials/{id}/challenge` for the new credential to issue a fresh OTP and receive `otpEncryptionTargetBundle` before verifying. For `PASSKEY`, the credential must be authenticated for the first time via `POST /auth/credentials/{id}/challenge` followed by `POST /auth/credentials/{id}/verify` to produce a session — there is no inline authentication challenge on the registration response. content: @@ -6184,6 +6190,12 @@ paths: type: string example: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21 responses: + '200': + description: 'The revocation''s underlying wallet-provider activity is still in flight — a `WalletOperationProcessing` body with `status: "PROCESSING"`. The client re-sends the same signed `DELETE` until it settles; the backend also reconciles the revocation to terminal on its own.' + content: + application/json: + schema: + $ref: '#/components/schemas/WalletOperationProcessing' '202': description: Challenge issued. The response contains `payloadToSign` plus a `requestId`. Build an API-key stamp over `payloadToSign` with the session API keypair of an existing verified credential on the same internal account (other than the one being revoked), then echo `requestId` on the retry. content: @@ -6294,11 +6306,11 @@ paths: signature: MEUCIQDYXBOpCWSWq2Ll4558GJKD2RoWg958lvJSB_GdeokxogIgWuEVQ7ee6AswQY0OsuQ6y8Ks6jhd45bDx92wjXKs900 responses: '200': - description: Authentication credential verified and session issued + description: 'Authentication credential verified and session issued (`AuthSession`); or, when the underlying wallet-provider activity is still in flight, a `WalletOperationProcessing` body with `status: "PROCESSING"` — the client re-sends the byte-identical request until it gets the session, and the backend also reconciles the activity to terminal on its own.' content: application/json: schema: - $ref: '#/components/schemas/AuthSession' + $ref: '#/components/schemas/AuthCredentialVerifyResponse' '202': description: Verification challenge issued. Returned only for OTP credentials, on the first leg of the secure OTP login flow. Build an API-key stamp over `payloadToSign` (the `verificationToken`) with the TEK keypair the client generated for this login, then resubmit the same request with that full stamp as `Grid-Wallet-Signature` and `requestId` echoed as `Request-Id` to receive the issued session on the signed retry. content: @@ -6391,11 +6403,11 @@ paths: value: {} responses: '200': - description: Challenge re-issued for the authentication credential. For `EMAIL_OTP` and `SMS_OTP` the body is a plain `AuthMethod` and a new OTP has been sent. For `PASSKEY` the body is a `PasskeyAuthChallenge` carrying the passkey `credentialId`, freshly issued `challenge`, `requestId`, and `expiresAt` required to complete reauthentication via `POST /auth/credentials/{id}/verify`. + description: Challenge re-issued for the authentication credential. For `EMAIL_OTP` and `SMS_OTP` the body is a plain `AuthMethod` and a new OTP has been sent. For `PASSKEY` the body is a `PasskeyAuthChallenge` carrying the passkey `credentialId`, freshly issued `challenge`, `requestId`, and `expiresAt` required to complete reauthentication via `POST /auth/credentials/{id}/verify`. When the OTP send's underlying wallet-provider activity is still in flight, the body is instead a `WalletOperationProcessing` carrying a `PROCESSING` status — re-request the challenge until the send settles; the backend also reconciles it to terminal on its own. content: application/json: schema: - $ref: '#/components/schemas/AuthCredentialResponseOneOf' + $ref: '#/components/schemas/AuthCredentialChallengeResponse' examples: emailOtp: summary: Email OTP challenge re-issued @@ -6538,6 +6550,12 @@ paths: type: string example: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21 responses: + '200': + description: 'The revocation''s underlying wallet-provider activity is still in flight — a `WalletOperationProcessing` body with `status: "PROCESSING"`. The client re-sends the same signed `DELETE` until it settles; the backend also reconciles the revocation to terminal on its own.' + content: + application/json: + schema: + $ref: '#/components/schemas/WalletOperationProcessing' '202': description: Challenge issued. The response contains `payloadToSign` plus a `requestId`. Build an API-key stamp over `payloadToSign` with the session API keypair of a verified session on the same internal account, then echo `requestId` on the retry. content: @@ -6620,6 +6638,12 @@ paths: value: clientPublicKey: 02f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31 responses: + '200': + description: 'The session refresh''s underlying wallet-provider activity is still in flight — a `WalletOperationProcessing` body with `status: "PROCESSING"`. The client re-sends the byte-identical signed retry until it gets the `201`; the backend also reconciles the activity to terminal on its own.' + content: + application/json: + schema: + $ref: '#/components/schemas/WalletOperationProcessing' '201': description: New authentication session created successfully. content: @@ -23455,6 +23479,26 @@ components: SMS_OTP: '#/components/schemas/SmsOtpCredentialCreateRequest' OAUTH: '#/components/schemas/OauthCredentialCreateRequest' PASSKEY: '#/components/schemas/PasskeyCredentialCreateRequest' + WalletOperationProcessing: + title: Wallet Operation Processing + description: '`200` response returned by an Embedded Wallet operation that the wallet provider has accepted but not yet settled — a consensus- or approval-gated activity that is still in flight. It is not an error and needs no client action beyond patience: the backend reconciles the operation to its terminal state on its own. The client MAY re-send the byte-identical request to converge sooner; the request is idempotent and returns the settled success response once the operation completes.' + type: object + required: + - status + properties: + status: + type: string + enum: + - PROCESSING + description: Always `PROCESSING`. Marks a still-in-flight operation whose terminal result is not yet available. + example: PROCESSING + message: + type: string + description: Human-readable explanation that the operation is still being processed and the same request may be retried. + example: This login is still being processed. Retry the same request in a moment. + example: + status: PROCESSING + message: This login is still being processed. Retry the same request in a moment. AuthMethodResponse: title: Auth Method Response description: |- @@ -23650,6 +23694,12 @@ components: format: date-time description: Timestamp after which the session is no longer valid and the session signing key must not be used to sign further requests. example: '2026-04-09T15:30:01Z' + AuthCredentialVerifyResponse: + title: Auth Credential Verify Response + description: 'Response body for `POST /auth/credentials/{id}/verify`. Normally an `AuthSession` — the issued session on successful verification. When the underlying wallet-provider activity is still in flight, this is instead a `WalletOperationProcessing` body with `status: "PROCESSING"` — the client re-sends the byte-identical request until it gets the session; the backend also reconciles the activity to terminal on its own.' + anyOf: + - $ref: '#/components/schemas/AuthSession' + - $ref: '#/components/schemas/WalletOperationProcessing' AuthCredentialChallengeRequest: title: Auth Credential Challenge Request description: Request body for `POST /auth/credentials/{id}/challenge`. Required when re-challenging a `PASSKEY` credential — must carry `clientPublicKey` so Grid can bake it into the session-creation payload the returned challenge is computed from. Ignored for `EMAIL_OTP` and `SMS_OTP`, where the credential type alone is sufficient because the OTP is delivered out-of-band. OAuth credentials do not use this endpoint; authenticate or reauthenticate them with `POST /auth/credentials/{id}/verify`. @@ -23703,6 +23753,12 @@ components: EMAIL_OTP: '#/components/schemas/AuthMethodResponse' SMS_OTP: '#/components/schemas/AuthMethodResponse' PASSKEY: '#/components/schemas/PasskeyAuthChallenge' + AuthCredentialChallengeResponse: + title: Auth Credential Challenge Response + description: 'Response body for `POST /auth/credentials/{id}/challenge`. Normally an `AuthCredentialResponseOneOf` — the re-issued challenge or re-sent OTP. When the OTP send''s underlying wallet-provider activity is still in flight, this is instead a `WalletOperationProcessing` body with `status: "PROCESSING"` — re-request the challenge until the send settles; the backend also reconciles it to terminal on its own.' + anyOf: + - $ref: '#/components/schemas/AuthCredentialResponseOneOf' + - $ref: '#/components/schemas/WalletOperationProcessing' SessionListResponse: type: object required: diff --git a/mintlify/snippets/global-accounts/authentication.mdx b/mintlify/snippets/global-accounts/authentication.mdx index 1f91faeaa..f6813890e 100644 --- a/mintlify/snippets/global-accounts/authentication.mdx +++ b/mintlify/snippets/global-accounts/authentication.mdx @@ -582,13 +582,15 @@ curl -X POST "$GRID_BASE_URL/auth/credentials/AuthMethod:019542f5-b3e7-1d02-0000 The TEK public key becomes the session API key. Unlike `OAUTH` and `PASSKEY` flows, `EMAIL_OTP` does **not** return `encryptedSessionSigningKey` — the client already holds the session signing key (the TEK private key it generated). +`verify` shares its terminal status code with the still-processing response: a `200` here is only a session if the body isn't `{ "status": "PROCESSING" }`. See handling a still-processing response — if you get `PROCESSING`, re-send the identical signed retry (same `encryptedOtpBundle`, `Grid-Wallet-Signature`, and `Request-Id`) until you get the session shown above. + **In sandbox, the OTP code is always `000000`** — encrypt that value in the bundle. The sandbox runs real HPKE end-to-end; the only shortcut is skipping email delivery. See Client keys for the encryption flow. ### Resending an OTP -If the code expires or the email didn't arrive, re-issue the challenge with `POST /auth/credentials/{id}/challenge`. This sends a fresh OTP email and leaves the `AuthMethod` otherwise untouched. +If the code expires or the email didn't arrive, re-issue the challenge with `POST /auth/credentials/{id}/challenge`. This sends a fresh OTP email and leaves the `AuthMethod` otherwise untouched. `challenge` can also return a still-processing `200` while the resend settles at the wallet provider — re-request the challenge until you get the `AuthMethod` back rather than a fresh OTP being sent twice. ```bash curl -X POST "$GRID_BASE_URL/auth/credentials/AuthMethod:019542f5-b3e7-1d02-0000-000000000004/challenge" \ @@ -662,6 +664,10 @@ sequenceDiagram C->>C: stamp(payloadToSign, sessionPrivateKey) C->>IB: { stamp } IB->>G: Same request
Grid-Wallet-Signature: stamp
Request-Id: requestId + alt still settling at the wallet provider + G-->>IB: 200 { status: "PROCESSING" } + IB->>G: Re-send the identical signed request + end G-->>IB: 2xx (terminal success) IB-->>C: done ``` @@ -673,6 +679,40 @@ Key rules: - The retry must reach Grid before `expiresAt` (typically 5 minutes from issue). - The `requestId` is returned as `Request:` and is single-use; reusing one yields `401`. +### Handling a still-processing response + +The signed retry can come back `200` with a `WalletOperationProcessing` body instead of the terminal success shown above: + +```json +{ + "status": "PROCESSING", + "message": "This login is still being processed. Retry the same request in a moment." +} +``` + +This means Grid's wallet provider accepted the operation but hasn't settled it yet — the request is not lost, and nothing failed. **Design for this as the normal path, not a rare edge case**: handle it the same way you handle the terminal success and error responses below, not as a bolted-on afterthought. + +Every signed-retry endpoint can return it on the retry step: + +| Endpoint | Action | +|---|---| +| `POST /auth/credentials` | Add a credential | +| `POST /auth/credentials/{id}/challenge` | Re-send an OTP / re-issue a challenge | +| `POST /auth/credentials/{id}/verify` | Log in / verify a credential | +| `POST /auth/sessions/{id}/refresh` | Refresh a session | +| `DELETE /auth/credentials/{id}` | Revoke a credential | +| `DELETE /auth/sessions/{id}` | Revoke a session | + +To handle it: + +1. **Re-send the exact same signed request** — identical body, `Grid-Wallet-Signature`, and `Request-Id`. Don't regenerate the stamp or start a fresh request; Grid correlates the retry with the same underlying operation and returns its real outcome once the provider settles, rather than starting a second one. +2. **Show a pending state in your UI** while you retry — "removing…" for a credential revoke, "signing in…" for a login — instead of treating `PROCESSING` as an error or leaving the caller blocked with no feedback. +3. **Keep retrying with backoff** until you get a terminal response — the success code above, or an error. Grid also reconciles the operation to its terminal state on its own, so even a client that stops retrying and checks back later (for example via `GET /auth/credentials` or `GET /auth/sessions`) will see the settled result. + + + `verify` and `challenge` already use `200` for their terminal success body (`AuthSession` or the challenge response). For those two, `200` alone doesn't tell you which case you're in — check the response body's `status` field for `"PROCESSING"` to distinguish it from a settled success. The other four endpoints (`add credential`, `session refresh`, `revoke credential`, `revoke session`) use `201` or `204` on success, so a `200` by itself already means still-processing. + + ### Add an additional credential Requires an active session on an *existing* credential on the same account. The first call uses the normal credential-create body; Grid detects the pre-existing credential and responds `202` instead of `201`. `OAUTH` and `PASSKEY` are the typical additional credential types. `EMAIL_OTP` can be added back only after the existing email OTP credential has been removed, because each account supports one. @@ -720,7 +760,7 @@ Requires an active session on an *existing* credential on the same account. The }' ``` - **Response (201):** a plain `AuthMethod`. + **Response (201):** a plain `AuthMethod`. If the underlying wallet-provider activity is still settling, this returns `200 { status: "PROCESSING" }` instead — see handling a still-processing response; re-send the identical signed request until you get the `201`. Activate the new credential the same way you would activate the first credential of that type — `OAUTH` goes straight to `POST /auth/credentials/{id}/verify` with a fresh `clientPublicKey`; `EMAIL_OTP` uses the `otpEncryptionTargetBundle` from the signed-retry registration response when present, or first calls `POST /auth/credentials/{id}/challenge` if the bundle is absent; `PASSKEY` first calls `POST /auth/credentials/{id}/challenge` with the `clientPublicKey` to get a Grid-issued WebAuthn challenge, then `POST /auth/credentials/{id}/verify` with the assertion and the `Request-Id` header. @@ -764,6 +804,6 @@ A credential is revoked by signing with a session from **a different credential -H "Request-Id: Request:9f7a2c10-5e88-4fb1-bd0e-1c3a8e7b2d45" ``` - **Response:** `204 No Content`. All active sessions issued by the revoked credential are also revoked. + **Response:** `204 No Content`. All active sessions issued by the revoked credential are also revoked. If the revocation is still settling at the wallet provider, this returns `200 { status: "PROCESSING" }` instead — re-send the identical `DELETE` until you get the `204`, and show the credential as "removing…" in your UI in the meantime rather than assuming success or failure. diff --git a/mintlify/snippets/global-accounts/managing-sessions.mdx b/mintlify/snippets/global-accounts/managing-sessions.mdx index 8f03b14b4..fbe41030b 100644 --- a/mintlify/snippets/global-accounts/managing-sessions.mdx +++ b/mintlify/snippets/global-accounts/managing-sessions.mdx @@ -38,7 +38,7 @@ The list endpoint returns all **active** sessions; expired sessions are not incl ## Refresh a session -Session refresh creates a new session signing key from an existing active session. Use this when the customer is still present and the current session is close to expiration. If the session has already expired, reauthenticate with the original credential instead. +Session refresh creates a new session signing key from an existing active session. Use this when the customer is still present and the current session is close to expiration. If the session has already expired, reauthenticate with the original credential instead. Refresh uses the same signed-retry pattern as credential management, including the possibility of a still-processing `200` response on the signed retry — re-send the same request until you get the `201` below. @@ -82,7 +82,7 @@ Session refresh creates a new session signing key from an existing active sessio ## Revoke a session -Session revocation uses the same signed-retry pattern as credential management. Unlike credential revocation, a session **can revoke itself** — this is how self-logout works: sign with the session key you are about to invalidate. +Session revocation uses the same signed-retry pattern as credential management, including a possible still-processing `200` response on the signed retry. Unlike credential revocation, a session **can revoke itself** — this is how self-logout works: sign with the session key you are about to invalidate. diff --git a/openapi.yaml b/openapi.yaml index e2b98ad11..1e90eb416 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -5968,6 +5968,12 @@ paths: - internal - hybrid responses: + '200': + description: 'An additional-credential setup leg''s underlying wallet-provider activity is still in flight — a `WalletOperationProcessing` body with `status: "PROCESSING"`. The client re-sends the byte-identical stamped retry (same `Request-Id`) until the credential is added; the backend also reconciles the activity to terminal on its own.' + content: + application/json: + schema: + $ref: '#/components/schemas/WalletOperationProcessing' '201': description: Authentication credential created successfully. The body is the created `AuthMethod`. For `EMAIL_OTP`, the nickname is the customer email tied to the internal account; for `SMS_OTP`, it is the customer phone number. OTP responses that trigger a secure OTP challenge carry `otpEncryptionTargetBundle` — the HPKE target bundle the client uses to encrypt the OTP attempt on the subsequent `POST /auth/credentials/{id}/verify`. First-time EMAIL_OTP wallet bootstrap responses may omit that bundle; if it is absent, call `POST /auth/credentials/{id}/challenge` for the new credential to issue a fresh OTP and receive `otpEncryptionTargetBundle` before verifying. For `PASSKEY`, the credential must be authenticated for the first time via `POST /auth/credentials/{id}/challenge` followed by `POST /auth/credentials/{id}/verify` to produce a session — there is no inline authentication challenge on the registration response. content: @@ -6184,6 +6190,12 @@ paths: type: string example: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21 responses: + '200': + description: 'The revocation''s underlying wallet-provider activity is still in flight — a `WalletOperationProcessing` body with `status: "PROCESSING"`. The client re-sends the same signed `DELETE` until it settles; the backend also reconciles the revocation to terminal on its own.' + content: + application/json: + schema: + $ref: '#/components/schemas/WalletOperationProcessing' '202': description: Challenge issued. The response contains `payloadToSign` plus a `requestId`. Build an API-key stamp over `payloadToSign` with the session API keypair of an existing verified credential on the same internal account (other than the one being revoked), then echo `requestId` on the retry. content: @@ -6294,11 +6306,11 @@ paths: signature: MEUCIQDYXBOpCWSWq2Ll4558GJKD2RoWg958lvJSB_GdeokxogIgWuEVQ7ee6AswQY0OsuQ6y8Ks6jhd45bDx92wjXKs900 responses: '200': - description: Authentication credential verified and session issued + description: 'Authentication credential verified and session issued (`AuthSession`); or, when the underlying wallet-provider activity is still in flight, a `WalletOperationProcessing` body with `status: "PROCESSING"` — the client re-sends the byte-identical request until it gets the session, and the backend also reconciles the activity to terminal on its own.' content: application/json: schema: - $ref: '#/components/schemas/AuthSession' + $ref: '#/components/schemas/AuthCredentialVerifyResponse' '202': description: Verification challenge issued. Returned only for OTP credentials, on the first leg of the secure OTP login flow. Build an API-key stamp over `payloadToSign` (the `verificationToken`) with the TEK keypair the client generated for this login, then resubmit the same request with that full stamp as `Grid-Wallet-Signature` and `requestId` echoed as `Request-Id` to receive the issued session on the signed retry. content: @@ -6391,11 +6403,11 @@ paths: value: {} responses: '200': - description: Challenge re-issued for the authentication credential. For `EMAIL_OTP` and `SMS_OTP` the body is a plain `AuthMethod` and a new OTP has been sent. For `PASSKEY` the body is a `PasskeyAuthChallenge` carrying the passkey `credentialId`, freshly issued `challenge`, `requestId`, and `expiresAt` required to complete reauthentication via `POST /auth/credentials/{id}/verify`. + description: Challenge re-issued for the authentication credential. For `EMAIL_OTP` and `SMS_OTP` the body is a plain `AuthMethod` and a new OTP has been sent. For `PASSKEY` the body is a `PasskeyAuthChallenge` carrying the passkey `credentialId`, freshly issued `challenge`, `requestId`, and `expiresAt` required to complete reauthentication via `POST /auth/credentials/{id}/verify`. When the OTP send's underlying wallet-provider activity is still in flight, the body is instead a `WalletOperationProcessing` carrying a `PROCESSING` status — re-request the challenge until the send settles; the backend also reconciles it to terminal on its own. content: application/json: schema: - $ref: '#/components/schemas/AuthCredentialResponseOneOf' + $ref: '#/components/schemas/AuthCredentialChallengeResponse' examples: emailOtp: summary: Email OTP challenge re-issued @@ -6538,6 +6550,12 @@ paths: type: string example: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21 responses: + '200': + description: 'The revocation''s underlying wallet-provider activity is still in flight — a `WalletOperationProcessing` body with `status: "PROCESSING"`. The client re-sends the same signed `DELETE` until it settles; the backend also reconciles the revocation to terminal on its own.' + content: + application/json: + schema: + $ref: '#/components/schemas/WalletOperationProcessing' '202': description: Challenge issued. The response contains `payloadToSign` plus a `requestId`. Build an API-key stamp over `payloadToSign` with the session API keypair of a verified session on the same internal account, then echo `requestId` on the retry. content: @@ -6620,6 +6638,12 @@ paths: value: clientPublicKey: 02f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31 responses: + '200': + description: 'The session refresh''s underlying wallet-provider activity is still in flight — a `WalletOperationProcessing` body with `status: "PROCESSING"`. The client re-sends the byte-identical signed retry until it gets the `201`; the backend also reconciles the activity to terminal on its own.' + content: + application/json: + schema: + $ref: '#/components/schemas/WalletOperationProcessing' '201': description: New authentication session created successfully. content: @@ -23455,6 +23479,26 @@ components: SMS_OTP: '#/components/schemas/SmsOtpCredentialCreateRequest' OAUTH: '#/components/schemas/OauthCredentialCreateRequest' PASSKEY: '#/components/schemas/PasskeyCredentialCreateRequest' + WalletOperationProcessing: + title: Wallet Operation Processing + description: '`200` response returned by an Embedded Wallet operation that the wallet provider has accepted but not yet settled — a consensus- or approval-gated activity that is still in flight. It is not an error and needs no client action beyond patience: the backend reconciles the operation to its terminal state on its own. The client MAY re-send the byte-identical request to converge sooner; the request is idempotent and returns the settled success response once the operation completes.' + type: object + required: + - status + properties: + status: + type: string + enum: + - PROCESSING + description: Always `PROCESSING`. Marks a still-in-flight operation whose terminal result is not yet available. + example: PROCESSING + message: + type: string + description: Human-readable explanation that the operation is still being processed and the same request may be retried. + example: This login is still being processed. Retry the same request in a moment. + example: + status: PROCESSING + message: This login is still being processed. Retry the same request in a moment. AuthMethodResponse: title: Auth Method Response description: |- @@ -23650,6 +23694,12 @@ components: format: date-time description: Timestamp after which the session is no longer valid and the session signing key must not be used to sign further requests. example: '2026-04-09T15:30:01Z' + AuthCredentialVerifyResponse: + title: Auth Credential Verify Response + description: 'Response body for `POST /auth/credentials/{id}/verify`. Normally an `AuthSession` — the issued session on successful verification. When the underlying wallet-provider activity is still in flight, this is instead a `WalletOperationProcessing` body with `status: "PROCESSING"` — the client re-sends the byte-identical request until it gets the session; the backend also reconciles the activity to terminal on its own.' + anyOf: + - $ref: '#/components/schemas/AuthSession' + - $ref: '#/components/schemas/WalletOperationProcessing' AuthCredentialChallengeRequest: title: Auth Credential Challenge Request description: Request body for `POST /auth/credentials/{id}/challenge`. Required when re-challenging a `PASSKEY` credential — must carry `clientPublicKey` so Grid can bake it into the session-creation payload the returned challenge is computed from. Ignored for `EMAIL_OTP` and `SMS_OTP`, where the credential type alone is sufficient because the OTP is delivered out-of-band. OAuth credentials do not use this endpoint; authenticate or reauthenticate them with `POST /auth/credentials/{id}/verify`. @@ -23703,6 +23753,12 @@ components: EMAIL_OTP: '#/components/schemas/AuthMethodResponse' SMS_OTP: '#/components/schemas/AuthMethodResponse' PASSKEY: '#/components/schemas/PasskeyAuthChallenge' + AuthCredentialChallengeResponse: + title: Auth Credential Challenge Response + description: 'Response body for `POST /auth/credentials/{id}/challenge`. Normally an `AuthCredentialResponseOneOf` — the re-issued challenge or re-sent OTP. When the OTP send''s underlying wallet-provider activity is still in flight, this is instead a `WalletOperationProcessing` body with `status: "PROCESSING"` — re-request the challenge until the send settles; the backend also reconciles it to terminal on its own.' + anyOf: + - $ref: '#/components/schemas/AuthCredentialResponseOneOf' + - $ref: '#/components/schemas/WalletOperationProcessing' SessionListResponse: type: object required: diff --git a/openapi/components/schemas/auth/AuthCredentialChallengeResponse.yaml b/openapi/components/schemas/auth/AuthCredentialChallengeResponse.yaml new file mode 100644 index 000000000..1dd58d310 --- /dev/null +++ b/openapi/components/schemas/auth/AuthCredentialChallengeResponse.yaml @@ -0,0 +1,11 @@ +title: Auth Credential Challenge Response +description: >- + Response body for `POST /auth/credentials/{id}/challenge`. Normally an + `AuthCredentialResponseOneOf` — the re-issued challenge or re-sent OTP. + When the OTP send's underlying wallet-provider activity is still in + flight, this is instead a `WalletOperationProcessing` body with + `status: "PROCESSING"` — re-request the challenge until the send + settles; the backend also reconciles it to terminal on its own. +anyOf: + - $ref: ./AuthCredentialResponseOneOf.yaml + - $ref: ../common/WalletOperationProcessing.yaml diff --git a/openapi/components/schemas/auth/AuthCredentialVerifyResponse.yaml b/openapi/components/schemas/auth/AuthCredentialVerifyResponse.yaml new file mode 100644 index 000000000..451c61b8a --- /dev/null +++ b/openapi/components/schemas/auth/AuthCredentialVerifyResponse.yaml @@ -0,0 +1,12 @@ +title: Auth Credential Verify Response +description: >- + Response body for `POST /auth/credentials/{id}/verify`. Normally an + `AuthSession` — the issued session on successful verification. When + the underlying wallet-provider activity is still in flight, this is + instead a `WalletOperationProcessing` body with `status: "PROCESSING"` + — the client re-sends the byte-identical request until it gets the + session; the backend also reconciles the activity to terminal on its + own. +anyOf: + - $ref: ./AuthSession.yaml + - $ref: ../common/WalletOperationProcessing.yaml diff --git a/openapi/components/schemas/common/WalletOperationProcessing.yaml b/openapi/components/schemas/common/WalletOperationProcessing.yaml new file mode 100644 index 000000000..6eecae4ad --- /dev/null +++ b/openapi/components/schemas/common/WalletOperationProcessing.yaml @@ -0,0 +1,30 @@ +title: Wallet Operation Processing +description: >- + `200` response returned by an Embedded Wallet operation that the wallet + provider has accepted but not yet settled — a consensus- or + approval-gated activity that is still in flight. It is not an error and + needs no client action beyond patience: the backend reconciles the + operation to its terminal state on its own. The client MAY re-send the + byte-identical request to converge sooner; the request is idempotent + and returns the settled success response once the operation completes. +type: object +required: + - status +properties: + status: + type: string + enum: + - PROCESSING + description: >- + Always `PROCESSING`. Marks a still-in-flight operation whose + terminal result is not yet available. + example: PROCESSING + message: + type: string + description: >- + Human-readable explanation that the operation is still being + processed and the same request may be retried. + example: This login is still being processed. Retry the same request in a moment. +example: + status: PROCESSING + message: This login is still being processed. Retry the same request in a moment. diff --git a/openapi/paths/auth/auth_credentials.yaml b/openapi/paths/auth/auth_credentials.yaml index f0232cbe2..7cc6f4b81 100644 --- a/openapi/paths/auth/auth_credentials.yaml +++ b/openapi/paths/auth/auth_credentials.yaml @@ -90,6 +90,18 @@ post: - internal - hybrid responses: + '200': + description: >- + An additional-credential setup leg's underlying wallet-provider + activity is still in flight — a `WalletOperationProcessing` body + with `status: "PROCESSING"`. The client re-sends the + byte-identical stamped retry (same `Request-Id`) until the + credential is added; the backend also reconciles the activity + to terminal on its own. + content: + application/json: + schema: + $ref: ../../components/schemas/common/WalletOperationProcessing.yaml '201': description: >- Authentication credential created successfully. The body is the diff --git a/openapi/paths/auth/auth_credentials_{id}.yaml b/openapi/paths/auth/auth_credentials_{id}.yaml index 0978bd58d..381dad8df 100644 --- a/openapi/paths/auth/auth_credentials_{id}.yaml +++ b/openapi/paths/auth/auth_credentials_{id}.yaml @@ -63,6 +63,17 @@ delete: type: string example: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21 responses: + '200': + description: >- + The revocation's underlying wallet-provider activity is still + in flight — a `WalletOperationProcessing` body with `status: + "PROCESSING"`. The client re-sends the same signed `DELETE` + until it settles; the backend also reconciles the revocation to + terminal on its own. + content: + application/json: + schema: + $ref: ../../components/schemas/common/WalletOperationProcessing.yaml '202': description: >- Challenge issued. The response contains `payloadToSign` plus a diff --git a/openapi/paths/auth/auth_credentials_{id}_challenge.yaml b/openapi/paths/auth/auth_credentials_{id}_challenge.yaml index 5df07e520..dc2dc7e05 100644 --- a/openapi/paths/auth/auth_credentials_{id}_challenge.yaml +++ b/openapi/paths/auth/auth_credentials_{id}_challenge.yaml @@ -80,11 +80,15 @@ post: new OTP has been sent. For `PASSKEY` the body is a `PasskeyAuthChallenge` carrying the passkey `credentialId`, freshly issued `challenge`, `requestId`, and `expiresAt` required to complete reauthentication - via `POST /auth/credentials/{id}/verify`. + via `POST /auth/credentials/{id}/verify`. When the OTP send's + underlying wallet-provider activity is still in flight, the body + is instead a `WalletOperationProcessing` carrying a `PROCESSING` + status — re-request the challenge until the send settles; the + backend also reconciles it to terminal on its own. content: application/json: schema: - $ref: ../../components/schemas/auth/AuthCredentialResponseOneOf.yaml + $ref: ../../components/schemas/auth/AuthCredentialChallengeResponse.yaml examples: emailOtp: summary: Email OTP challenge re-issued diff --git a/openapi/paths/auth/auth_credentials_{id}_verify.yaml b/openapi/paths/auth/auth_credentials_{id}_verify.yaml index ae40fcd88..e6d050957 100644 --- a/openapi/paths/auth/auth_credentials_{id}_verify.yaml +++ b/openapi/paths/auth/auth_credentials_{id}_verify.yaml @@ -140,11 +140,17 @@ post: signature: MEUCIQDYXBOpCWSWq2Ll4558GJKD2RoWg958lvJSB_GdeokxogIgWuEVQ7ee6AswQY0OsuQ6y8Ks6jhd45bDx92wjXKs900 responses: '200': - description: Authentication credential verified and session issued + description: >- + Authentication credential verified and session issued + (`AuthSession`); or, when the underlying wallet-provider + activity is still in flight, a `WalletOperationProcessing` body + with `status: "PROCESSING"` — the client re-sends the + byte-identical request until it gets the session, and the + backend also reconciles the activity to terminal on its own. content: application/json: schema: - $ref: ../../components/schemas/auth/AuthSession.yaml + $ref: ../../components/schemas/auth/AuthCredentialVerifyResponse.yaml '202': description: >- Verification challenge issued. Returned only for OTP credentials, diff --git a/openapi/paths/auth/auth_sessions_{id}.yaml b/openapi/paths/auth/auth_sessions_{id}.yaml index 7b2fa0755..c2b121dbd 100644 --- a/openapi/paths/auth/auth_sessions_{id}.yaml +++ b/openapi/paths/auth/auth_sessions_{id}.yaml @@ -59,6 +59,17 @@ delete: type: string example: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21 responses: + '200': + description: >- + The revocation's underlying wallet-provider activity is still + in flight — a `WalletOperationProcessing` body with `status: + "PROCESSING"`. The client re-sends the same signed `DELETE` + until it settles; the backend also reconciles the revocation to + terminal on its own. + content: + application/json: + schema: + $ref: ../../components/schemas/common/WalletOperationProcessing.yaml '202': description: >- Challenge issued. The response contains `payloadToSign` plus a diff --git a/openapi/paths/auth/auth_sessions_{id}_refresh.yaml b/openapi/paths/auth/auth_sessions_{id}_refresh.yaml index 9cf9182aa..4e5647547 100644 --- a/openapi/paths/auth/auth_sessions_{id}_refresh.yaml +++ b/openapi/paths/auth/auth_sessions_{id}_refresh.yaml @@ -73,6 +73,17 @@ post: value: clientPublicKey: 02f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31 responses: + '200': + description: >- + The session refresh's underlying wallet-provider activity is + still in flight — a `WalletOperationProcessing` body with + `status: "PROCESSING"`. The client re-sends the byte-identical + signed retry until it gets the `201`; the backend also + reconciles the activity to terminal on its own. + content: + application/json: + schema: + $ref: ../../components/schemas/common/WalletOperationProcessing.yaml '201': description: New authentication session created successfully. content: