Skip to content

Add auth session refresh endpoints#451

Merged
DhruvPareek merged 2 commits into
mainfrom
auth-session-refresh-openapi
May 12, 2026
Merged

Add auth session refresh endpoints#451
DhruvPareek merged 2 commits into
mainfrom
auth-session-refresh-openapi

Conversation

@DhruvPareek
Copy link
Copy Markdown
Contributor

@DhruvPareek DhruvPareek commented May 8, 2026

Summary

  • Replace the two session reauthentication endpoints with a single signed-retry action: POST /auth/sessions/{id}/refresh
  • Rename the request schema to AuthSessionRefreshRequest and reuse SignedRequestChallenge for the initial 202 response
  • Wire the new refresh method into Stainless and regenerate bundled OpenAPI specs

Endpoint shape

Initial call

POST /auth/sessions/{id}/refresh
Authorization: Basic <client_id:client_secret>
Content-Type: application/json
{
  "clientPublicKey": "04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2"
}

Returns 202 with SignedRequestChallenge:

{
  "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"
}

Signed retry

POST /auth/sessions/{id}/refresh
Authorization: Basic <client_id:client_secret>
Content-Type: application/json
Grid-Wallet-Signature: <api-key-stamp-over-payloadToSign>
Request-Id: Request:019542f5-b3e7-1d02-0000-000000000010
{
  "clientPublicKey": "04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2"
}

Returns 201 with AuthSession:

{
  "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"
}

The original session must still be active on both calls. If it has expired, clients should use the credential reauthentication flow.

Validation

  • npm run lint:openapi

@vercel
Copy link
Copy Markdown

vercel Bot commented May 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
grid-flow-builder Ready Ready Preview, Comment May 12, 2026 0:55am

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

✱ Stainless preview builds

This PR will update the grid SDKs with the following commit messages.

kotlin

feat(api): add issueChallenge and verifyChallenge methods to sessions

openapi

feat(api): add session reauthentication endpoints to auth/sessions

python

feat(api): add issue_challenge and verify_challenge methods to auth sessions

typescript

feat(api): add issueChallenge/verifyChallenge to auth sessions

Edit this comment to update them. They will appear in their respective SDK's changelogs.

grid-python studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ✅test ✅

pip install https://pkg.stainless.com/s/grid-python/e2b4290eeb0cbb55e1a9917783c1c203788ea189/grid-0.0.1-py3-none-any.whl
grid-kotlin studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ✅test ✅

grid-typescript studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ❗lint ❗test ❗

grid-openapi studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-05-08 00:49:01 UTC

@DhruvPareek DhruvPareek marked this pull request as ready for review May 8, 2026 17:12
@DhruvPareek DhruvPareek requested a review from pengying May 8, 2026 17:12
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 8, 2026

Greptile Summary

Adds a two-step mid-session reauthentication flow (POST /auth/sessions/{id}/challengePOST /auth/sessions/{id}/verify) that lets an active Embedded Wallet session be extended without re-running the credential-specific auth flow. A new AuthSessionReauthRequest schema is introduced and shared by both endpoints, and the Stainless config and bundled specs are regenerated.

  • POST /auth/sessions/{id}/challenge issues a signed Turnkey payload for the client to stamp; responds 202 with SignedRequestChallenge.
  • POST /auth/sessions/{id}/verify consumes the stamped payload via Grid-Wallet-Signature + Request-Id headers and returns a new AuthSession (201) with encryptedSessionSigningKey sealed to the client's public key.
  • AuthSessionReauthRequest enforces the SEC1 uncompressed P-256 format via regex; AuthSession and SignedRequestChallenge are reused without changes to their schemas.

Confidence Score: 4/5

The change is additive — two new endpoints and one new schema — and does not touch any existing endpoint logic. Safe to merge.

The signed-retry flow is correctly structured with the stamp carried in headers and the session ID in the path. The only gaps are documentation quality: the challenge endpoint's 401 description is bare compared to every other auth endpoint, and the minLength/maxLength on the public key schema are redundant with the regex. Neither affects runtime behaviour.

openapi/paths/auth/auth_sessions_{id}_challenge.yaml — the 401 response description would benefit from the same level of detail as its sibling verify endpoint.

Important Files Changed

Filename Overview
openapi/paths/auth/auth_sessions_{id}_challenge.yaml New POST endpoint for issuing a mid-session reauthentication challenge; well-structured but the 401 error description is bare ("Unauthorized") with no detail about trigger conditions, unlike peer endpoints.
openapi/paths/auth/auth_sessions_{id}_verify.yaml New POST endpoint for completing mid-session reauthentication; thorough 401 description, correct 201 response, required headers (Grid-Wallet-Signature, Request-Id) all documented. No issues found.
openapi/components/schemas/auth/AuthSessionReauthRequest.yaml New schema for the shared request body; pattern correctly enforces SEC1 uncompressed P-256 format, but minLength/maxLength are redundant with the pattern constraint.
openapi/components/schemas/auth/AuthSession.yaml Description updated to reference the new session verify endpoint alongside the existing credential verify; change is accurate and well-worded.
.stainless/stainless.yml Wires challenge and verify methods under auth.sessions with correct endpoints and body_param_name; models section correctly registers the three new/reused schemas.
openapi/openapi.yaml Root spec correctly adds $ref entries for the two new path files in the right position between auth_sessions_{id} and /agents.
openapi.yaml Generated bundle; changes are consistent with the source spec additions in openapi/.
mintlify/openapi.yaml Generated Mintlify bundle; correctly mirrors the source spec additions including both new paths and the AuthSessionReauthRequest schema.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Grid API
    participant Turnkey

    Note over Client,Grid API: Session approaching expiry (still active)

    Client->>Grid API: POST /auth/sessions/{id}/challenge<br/>BasicAuth + clientPublicKey
    Grid API->>Turnkey: Build CREATE_READ_WRITE_SESSION_V2 payload<br/>(bind clientPublicKey)
    Grid API-->>Client: 202 SignedRequestChallenge<br/>(payloadToSign, requestId, expiresAt)

    Note over Client: Sign payloadToSign with<br/>current session signing key

    Client->>Grid API: POST /auth/sessions/{id}/verify<br/>BasicAuth + Grid-Wallet-Signature + Request-Id + clientPublicKey
    Grid API->>Grid API: Verify signature matches challenge<br/>Verify requestId unexpired<br/>Verify clientPublicKey matches
    Grid API->>Turnkey: Execute CREATE_READ_WRITE_SESSION_V2
    Grid API-->>Client: 201 AuthSession<br/>(encryptedSessionSigningKey sealed to clientPublicKey)

    Note over Client: Decrypt encryptedSessionSigningKey<br/>Use new signing key for future requests
Loading

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
openapi/paths/auth/auth_sessions_{id}_challenge.yaml:57-62
**Sparse `401` description inconsistent with the rest of the auth flow**

The challenge endpoint's `401` response is documented as only "Unauthorized", giving API consumers no guidance on what conditions trigger it. The `POST /auth/credentials/{id}/verify` and `POST /auth/sessions/{id}/verify` endpoints both enumerate concrete trigger conditions (expired OTP, bad signature, mismatched `clientPublicKey`, etc.). An expired session hitting this endpoint would presumably also return `401`, but there is nothing here to tell clients that — or to distinguish it from a bad `BasicAuth` credential. Developers integrating the challenge step will have to discover error conditions by trial and error.

### Issue 2 of 2
openapi/components/schemas/auth/AuthSessionReauthRequest.yaml:14-16
The `minLength` and `maxLength` constraints are redundant — `pattern: "^04[0-9a-fA-F]{128}$"` already anchors to exactly 130 characters. Redundant validators are harmless but can confuse validators that surface all applicable failures, making the schema harder to maintain.

```suggestion
    pattern: "^04[0-9a-fA-F]{128}$"
```

Reviews (1): Last reviewed commit: "Add auth session refresh endpoints" | Re-trigger Greptile

Comment on lines +57 to +62
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':
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Sparse 401 description inconsistent with the rest of the auth flow

The challenge endpoint's 401 response is documented as only "Unauthorized", giving API consumers no guidance on what conditions trigger it. The POST /auth/credentials/{id}/verify and POST /auth/sessions/{id}/verify endpoints both enumerate concrete trigger conditions (expired OTP, bad signature, mismatched clientPublicKey, etc.). An expired session hitting this endpoint would presumably also return 401, but there is nothing here to tell clients that — or to distinguish it from a bad BasicAuth credential. Developers integrating the challenge step will have to discover error conditions by trial and error.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/paths/auth/auth_sessions_{id}_challenge.yaml
Line: 57-62

Comment:
**Sparse `401` description inconsistent with the rest of the auth flow**

The challenge endpoint's `401` response is documented as only "Unauthorized", giving API consumers no guidance on what conditions trigger it. The `POST /auth/credentials/{id}/verify` and `POST /auth/sessions/{id}/verify` endpoints both enumerate concrete trigger conditions (expired OTP, bad signature, mismatched `clientPublicKey`, etc.). An expired session hitting this endpoint would presumably also return `401`, but there is nothing here to tell clients that — or to distinguish it from a bad `BasicAuth` credential. Developers integrating the challenge step will have to discover error conditions by trial and error.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

Comment on lines +14 to +16
pattern: "^04[0-9a-fA-F]{128}$"
minLength: 130
maxLength: 130
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The minLength and maxLength constraints are redundant — pattern: "^04[0-9a-fA-F]{128}$" already anchors to exactly 130 characters. Redundant validators are harmless but can confuse validators that surface all applicable failures, making the schema harder to maintain.

Suggested change
pattern: "^04[0-9a-fA-F]{128}$"
minLength: 130
maxLength: 130
pattern: "^04[0-9a-fA-F]{128}$"
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/auth/AuthSessionReauthRequest.yaml
Line: 14-16

Comment:
The `minLength` and `maxLength` constraints are redundant — `pattern: "^04[0-9a-fA-F]{128}$"` already anchors to exactly 130 characters. Redundant validators are harmless but can confuse validators that surface all applicable failures, making the schema harder to maintain.

```suggestion
    pattern: "^04[0-9a-fA-F]{128}$"
```

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

✱ Stainless preview builds for grid

This PR will update the grid SDKs with the following commit messages.

kotlin

feat(api): add issueChallenge and verifyChallenge methods to sessions

openapi

feat(api): add session reauthentication endpoints to auth/sessions

python

feat(api): add issue_challenge and verify_challenge methods to auth sessions

typescript

feat(api): add issueChallenge/verifyChallenge to auth sessions
⚠️ grid-kotlin studio · code

Your SDK build had at least one "error" diagnostic.
generate ❗build ✅lint ✅test ✅

⚠️ grid-openapi studio · code

Your SDK build had at least one "error" diagnostic.
generate ❗

⚠️ grid-typescript studio · code

Your SDK build had a failure in the build CI job, which is a regression from the base state.
generate ❗build ❗lint ❗test ❗

⚠️ grid-python studio · code

Your SDK build had at least one "error" diagnostic.
generate ❗build ✅lint ✅test ✅

pip install https://pkg.stainless.com/s/grid-python/03f9d55bce19bcdad20c3f3627ab893f52482854/grid-0.0.1-py3-none-any.whl

This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-05-12 17:06:07 UTC

Copy link
Copy Markdown
Contributor

@pengying pengying left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait why do you need a challenge and verify on sessions in addition to the ones on credentials?

Copy link
Copy Markdown
Contributor Author

Forgot to include this in the PR description, it's in the AUTH ENDPOINTS doc
Screenshot 2026-05-11 at 2.11.29 PM.png

@DhruvPareek DhruvPareek requested a review from pengying May 11, 2026 21:20
@DhruvPareek DhruvPareek force-pushed the auth-email-otp-update-openapi branch from 75d2847 to e1c65a5 Compare May 11, 2026 21:28
@DhruvPareek DhruvPareek force-pushed the auth-email-otp-update-openapi branch from e1c65a5 to 4adb176 Compare May 11, 2026 22:13
@DhruvPareek DhruvPareek force-pushed the auth-session-refresh-openapi branch from 4c1aa5d to b0d147f Compare May 11, 2026 22:14
@DhruvPareek DhruvPareek force-pushed the auth-email-otp-update-openapi branch from 4adb176 to aadbb4a Compare May 11, 2026 22:14
@DhruvPareek DhruvPareek force-pushed the auth-email-otp-update-openapi branch 2 times, most recently from 4808147 to ee39422 Compare May 11, 2026 22:39
@DhruvPareek DhruvPareek force-pushed the auth-session-refresh-openapi branch from b0d147f to def6040 Compare May 11, 2026 22:39
Copy link
Copy Markdown
Contributor Author

this allows a user to get a new session using their session token rather than having to retrieve an otp code or hit a passkey or sign in via oauth again. It's simpler re-auth with an existing token

@DhruvPareek DhruvPareek changed the base branch from auth-email-otp-update-openapi to graphite-base/451 May 11, 2026 23:07
@DhruvPareek DhruvPareek force-pushed the auth-session-refresh-openapi branch from def6040 to 5f54cd7 Compare May 11, 2026 23:07
@graphite-app graphite-app Bot changed the base branch from graphite-base/451 to main May 11, 2026 23:08
@DhruvPareek DhruvPareek force-pushed the auth-session-refresh-openapi branch from 5f54cd7 to d588311 Compare May 11, 2026 23:08
Copy link
Copy Markdown
Contributor

do you feel like it's challenge verify here or is it just a refresh that needs a signature? one option could be to use a single endpoint with the 202 flow eg

/auth/sessions/{id}/refresh

No security concerns with the client continually refreshing the session here right?

Copy link
Copy Markdown
Contributor Author

I like your idea, it's cleaner than the way I had it

Copy link
Copy Markdown
Contributor Author

updated the PR to use /auth/sessions/{id}/refresh

@DhruvPareek DhruvPareek merged commit 6a8a9a9 into main May 12, 2026
9 of 10 checks passed
@DhruvPareek DhruvPareek deleted the auth-session-refresh-openapi branch May 12, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants