add DELETE /auth/credentials/{id} to revoke authentication credentials#369
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
✱ Stainless preview buildsThis PR will update the kotlin openapi python typescript Edit this comment to update them. They will appear in their respective SDK's changelogs. ✅ grid-python studio · code · diff
✅ grid-typescript studio · code · diff
✅ grid-openapi studio · code · diff
✅ grid-kotlin studio · code · diff
This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push. |
79a749a to
d0f0803
Compare
108f6cf to
fec18b2
Compare
d0f0803 to
4517a0d
Compare
fec18b2 to
088d2dc
Compare
4517a0d to
b280a16
Compare
088d2dc to
9f6c7a1
Compare
9f6c7a1 to
52fcd4f
Compare
b280a16 to
2da0bb2
Compare
52fcd4f to
9198355
Compare
Greptile SummaryThis PR adds Confidence Score: 5/5Safe to merge; only P2 style findings remain. All findings are P2: a stale example timestamp in SignedRequestChallenge and a missing base64 == padding on payloadToSign. Neither affects runtime behavior or API correctness. The endpoint design, schema composition, Stainless wiring, and generated bundles all look correct and consistent with existing patterns. openapi/components/schemas/common/SignedRequestChallenge.yaml — minor example inconsistencies noted above.
|
| Filename | Overview |
|---|---|
| openapi/paths/auth/auth_credentials_{id}.yaml | New DELETE operation implementing the two-step signed-retry revocation flow; mirrors the POST /auth/credentials pattern correctly, with well-documented parameters and all expected response codes. |
| openapi/components/schemas/common/SignedRequestChallenge.yaml | New reusable base schema for signed-retry challenges; minor issues: payloadToSign example is missing base64 == padding (inconsistent with existing examples), and expiresAt example date is already in the past. |
| openapi/components/schemas/auth/AuthCredentialDeleteChallenge.yaml | Correct allOf composition of SignedRequestChallenge + credential-specific fields (id, type); required fields and $ref to AuthMethodType are properly set. |
| .stainless/stainless.yml | Adds delete method and auth_credential_delete_challenge/signed_request_challenge models to Stainless config; follows existing patterns. |
| openapi/openapi.yaml | Adds the /auth/credentials/{id} path reference in the correct position; no issues. |
| openapi.yaml | Generated bundle updated with the new DELETE endpoint and schemas; expected artifact from running make build. |
| mintlify/openapi.yaml | Generated Mintlify bundle updated with the new DELETE endpoint and schemas; expected artifact from running make build. |
Sequence Diagram
sequenceDiagram
participant Client
participant API as DELETE /auth/credentials/{id}
Client->>API: DELETE /auth/credentials/{id} (no headers)
API-->>Client: 202 AuthCredentialDeleteChallenge
Note right of API: payloadToSign, requestId, expiresAt
Note over Client: Sign payloadToSign with session
Note over Client: private key of a *different*
Note over Client: verified credential
Client->>API: DELETE /auth/credentials/{id}
Note right of Client: + Grid-Wallet-Signature header
Note right of Client: + Request-Id header
alt Signature valid & different credential
API-->>Client: 204 No Content (revoked)
else Last remaining credential
API-->>Client: 400 Bad Request
else Invalid/expired signature
API-->>Client: 401 Unauthorized
else Credential not found
API-->>Client: 404 Not Found
end
Prompt To Fix All With AI
This is a comment left during a code review.
Path: openapi/components/schemas/common/SignedRequestChallenge.yaml
Line: 34-36
Comment:
**`expiresAt` example timestamp is already in the past**
The example value `'2026-04-08T15:35:00Z'` predates the current date (2026-04-22), which means docs and SDK tooling will render a stale timestamp that looks incorrect to readers. Consider advancing it to a future date that won't expire immediately on publication.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: openapi/components/schemas/common/SignedRequestChallenge.yaml
Line: 22
Comment:
**`payloadToSign` example missing base64 padding**
The example `Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg` is missing the standard `==` padding. Existing uses of the same logical value in `openapi/paths/auth/auth_credentials.yaml` (lines 140/147) consistently include the trailing `==`. Strict base64 parsers will reject the unpadded form; aligning with the existing examples avoids any confusion.
```suggestion
example: Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg==
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat: add DELETE /auth/credentials/{id} ..." | Re-trigger Greptile
| Timestamp after which this challenge is no longer valid. The | ||
| signed retry must be submitted before this time. | ||
| example: '2026-04-08T15:35:00Z' |
There was a problem hiding this comment.
expiresAt example timestamp is already in the past
The example value '2026-04-08T15:35:00Z' predates the current date (2026-04-22), which means docs and SDK tooling will render a stale timestamp that looks incorrect to readers. Consider advancing it to a future date that won't expire immediately on publication.
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/common/SignedRequestChallenge.yaml
Line: 34-36
Comment:
**`expiresAt` example timestamp is already in the past**
The example value `'2026-04-08T15:35:00Z'` predates the current date (2026-04-22), which means docs and SDK tooling will render a stale timestamp that looks incorrect to readers. Consider advancing it to a future date that won't expire immediately on publication.
How can I resolve this? If you propose a fix, please make it concise.| verified authentication credential. The resulting signature is | ||
| passed as the `Grid-Wallet-Signature` header on the retry of the | ||
| originating request to complete the operation. | ||
| example: Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg |
There was a problem hiding this comment.
payloadToSign example missing base64 padding
The example Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg is missing the standard == padding. Existing uses of the same logical value in openapi/paths/auth/auth_credentials.yaml (lines 140/147) consistently include the trailing ==. Strict base64 parsers will reject the unpadded form; aligning with the existing examples avoids any confusion.
| example: Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg | |
| example: Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg== |
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/common/SignedRequestChallenge.yaml
Line: 22
Comment:
**`payloadToSign` example missing base64 padding**
The example `Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg` is missing the standard `==` padding. Existing uses of the same logical value in `openapi/paths/auth/auth_credentials.yaml` (lines 140/147) consistently include the trailing `==`. Strict base64 parsers will reject the unpadded form; aligning with the existing examples avoids any confusion.
```suggestion
example: Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg==
```
How can I resolve this? If you propose a fix, please make it concise.9198355 to
b8d867f
Compare
2da0bb2 to
5d420cd
Compare
…entials
New revocation endpoint for the Embedded Wallet Auth surface. Revocation is a two-step signed-retry flow (same pattern as the add-additional-credential flow on POST /auth/credentials), because it must be authorized by a session on a *different* credential on the same internal account.
**Flow**
1. `DELETE /auth/credentials/{id}` with no headers → `202` `AuthCredentialDeleteChallenge` (`id`, `type`, `payloadToSign`, `requestId`, `expiresAt`).
2. Client signs `payloadToSign` with the session private key of another verified credential on the same internal account and retries the request with `Grid-Wallet-Signature` + `Request-Id` headers → `204`.
**Schemas added**
- `SignedRequestChallenge` (common) — shared base for two-step signed-retry challenge responses. Holds the three fields every challenge variant carries: `payloadToSign`, `requestId`, `expiresAt`. Each variant composes this base via `allOf` and adds its own resource `id` (and `type`, when applicable) with variant-specific description and example.
- `AuthCredentialDeleteChallenge` — `allOf(SignedRequestChallenge, { id, type: AuthMethodType })`. `id` points at the credential being revoked.
**Wire-up**
- New path file `openapi/paths/auth/auth_credentials_{id}.yaml` with the `delete` operation plus shared `Grid-Wallet-Signature` and `Request-Id` headers, modelled on `POST /auth/credentials`.
- `openapi/openapi.yaml` registers the new path.
- `.stainless/stainless.yml` adds `delete: delete /auth/credentials/{id}` to the `auth.credentials` methods and registers `AuthCredentialDeleteChallenge` + the shared `SignedRequestChallenge` (under `$shared`) as models.
- Bundled `openapi.yaml` + `mintlify/openapi.yaml` regenerated.
**Design notes**
- `id` is kept in the variant (not the base) so each variant owns its resource-specific description and example (`AuthMethod:…`, `Session:…`, `InternalAccount:…`). Avoids relying on `allOf` property overrides, which tooling (Mintlify, Stainless) handles inconsistently.
- `SignedRequestChallenge` is also used by the next two PRs in the stack (`SessionDeleteChallenge`, `InternalAccountExportChallenge`). Refactored up-front rather than deferred so the three sites land on the same base from day one.
- `AuthCredentialAdditionalChallenge` (already in main) has an overlapping shape but a different semantic role (registering vs. revoking). Leaving it alone for now; it can be migrated onto `SignedRequestChallenge` as a follow-up if desired.
**Notes**
- The account must retain at least one credential after revocation; revoking the last remaining credential is rejected with `400`.
b8d867f to
65bd260
Compare
5d420cd to
05ba4d6
Compare

New revocation endpoint for the Embedded Wallet Auth surface. Revocation is a two-step signed-retry flow (same pattern as the add-additional-credential flow on POST /auth/credentials), because it must be authorized by a session on a different credential on the same internal account.
Flow
DELETE /auth/credentials/{id}with no headers →202AuthCredentialDeleteChallenge(id,type,payloadToSign,requestId,expiresAt).payloadToSignwith the session private key of another verified credential on the same internal account and retries the request withGrid-Wallet-Signature+Request-Idheaders →204.Schemas added
SignedRequestChallenge(common) — shared base for two-step signed-retry challenge responses. Holds the three fields every challenge variant carries:payloadToSign,requestId,expiresAt. Each variant composes this base viaallOfand adds its own resourceid(andtype, when applicable) with variant-specific description and example.AuthCredentialDeleteChallenge—allOf(SignedRequestChallenge, { id, type: AuthMethodType }).idpoints at the credential being revoked.Wire-up
openapi/paths/auth/auth_credentials_{id}.yamlwith thedeleteoperation plus sharedGrid-Wallet-SignatureandRequest-Idheaders, modelled onPOST /auth/credentials.Design notes
SignedRequestChallengeis also used by the next two PRs in the stack (SessionDeleteChallenge,InternalAccountExportChallenge).AuthCredentialAdditionalChallenge(already in main) has an overlapping shape but a different semantic role (registering vs. revoking). Those auth endpoints get updated to useSignedRequestChallengein PR refactor: migrate AuthCredentialAdditionalChallenge onto SignedRequestChallenge base #373Notes
400.