Skip to content

✨ server: add auth for wallet extensions#1070

Merged
cruzdanilo merged 2 commits into
mainfrom
wallet-extension-auth
Jun 29, 2026
Merged

✨ server: add auth for wallet extensions#1070
cruzdanilo merged 2 commits into
mainfrom
wallet-extension-auth

Conversation

@aguxez

@aguxez aguxez commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add iOS wallet extension bearer token issuance during authentication and accept it for GET /api/card?scope=provisioning
  • Send a Client-Platform header from the mobile client while preserving existing miniapp Client-Fid behavior
  • Add server coverage for wallet extension auth, provisioning access, and token verification

Testing

  • pnpm nx test:ts server
  • pnpm nx test:eslint server
  • pnpm nx test:vi server -- test/api/auth.test.ts test/api/card-wallet-extension.test.ts test/middleware/auth-wallet-extension.test.ts

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Apple Wallet extension authentication support for iOS users
    • Implemented automatic platform detection for iOS and Android clients
    • Enabled wallet extension bearer token authentication for card provisioning
  • Tests

    • Added comprehensive test coverage for wallet extension authentication flows and card operations

@changeset-bot

changeset-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 73aa075

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@exactly/server Patch
@exactly/mobile Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR implements wallet-extension bearer token authentication for iOS card provisioning. It adds token creation/verification utilities, extends the authentication endpoint to conditionally generate tokens on iOS, introduces a multi-path cardAuth middleware supporting cookies, sessions, and bearer tokens, integrates the card endpoint with the new middleware, provides comprehensive test coverage for all auth flows, ensures the client sends platform headers, and publishes release notes.

Changes

Wallet Extension Authentication and Card Provisioning

Layer / File(s) Summary
Wallet extension token creation and verification
server/utils/walletExtension.ts
createToken and verifyToken functions provide HS256 JWT helpers with audience "wallet-extension", credential ID, and fixed "card:provisioning" scope. Token expiration and Valibot schema validation are included.
Authentication endpoint schema and wallet-extension response
server/api/auth/authentication.ts
Authentication schema extends with optional walletExtensionToken and walletExtensionTokenExpires fields. POST handler validates optional Client-Platform header (android/ios), reads it into platform, and conditionally spreads wallet-extension credentials into SIWE and WebAuthn success responses for iOS only.
CardAuth middleware with cookie/session/bearer fallback
server/middleware/cardAuth.ts
New middleware authenticates via signed credential_id cookie first, then server session with wallet-address resolution, and finally Bearer token verification when scope=provisioning. Returns 401 on invalid paths and attaches cookie.credentialId to validated request data on success.
Card provisioning route configuration and OpenAPI
server/api/card.ts, server/script/openapi.ts
Card GET route switches from auth() to cardAuth() middleware. Route description documents wallet-extension bearer constraints (provisioning scope only, no sessionid). OpenAPI adds walletExtensionAuth bearer security scheme.
Authentication API wallet-extension token tests
server/test/api/auth.test.ts
Tests updated to validate responses with Valibot parse(). iOS webauthn and SIWE tests assert token fields presence and verify token contents (credentialId and scope). Android test confirms fields absent; no-platform test confirms fields undefined.
CardAuth middleware authentication path tests
server/test/middleware/cardAuth.test.ts
Comprehensive suite covering cookie auth bypass, session-based wallet resolution (primary/single/ambiguous/missing scenarios), bearer token acceptance (including lowercase "bearer" scheme), and bearer token rejection (sessionid present, mixed scopes, invalid schemes, missing/expired/malformed tokens).
Card provisioning endpoint integration tests
server/test/api/card-better-auth.test.ts, server/test/api/card-wallet-extension.test.ts
Two test suites: card-better-auth exercises session auth with sessionid header and validates card/user/secret/PIN response shape; card-wallet-extension exercises bearer token provisioning auth, mocks Panda utilities, asserts 200 and Cache-Control header, verifies PIN/secret not called.
Client platform header transmission and release notes
src/utils/server.ts, server/test/mocks/auth.ts, .changeset/*
Client fetch override builds Headers, sets Client-Platform (ios/android), and sends via native fetch in non-mini-app mode. Test mocks augmented with cardAuth middleware mock. Release changesets document wallet extension auth (server) and client platform header (mobile).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • cruzdanilo
  • nfmelendez
  • dieguezguille
  • franm91
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding authentication support for wallet extensions on the server.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wallet-extension-auth
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch wallet-extension-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces wallet extension authentication for iOS clients. It adds support for generating and verifying a wallet extension bearer token, updates the authentication endpoints to return this token for iOS platforms, and modifies the authentication middleware to support bearer token authentication for card provisioning. A review comment identifies an issue in the authentication middleware where the scope query parameter, which can be an array, is not correctly checked for the "provisioning" value, potentially causing valid requests to be rejected. A code suggestion is provided to handle both string and array types for scope.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread server/middleware/auth.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b1dd2131-b28c-4f77-b7d7-30dd62e2c176

📥 Commits

Reviewing files that changed from the base of the PR and between 4e493dd and 81ae104.

📒 Files selected for processing (10)
  • .changeset/brave-otters-serve.md
  • .changeset/clever-ravens-send.md
  • server/api/auth/authentication.ts
  • server/api/card.ts
  • server/middleware/auth.ts
  • server/test/api/auth.test.ts
  • server/test/api/card-wallet-extension.test.ts
  • server/test/middleware/auth-wallet-extension.test.ts
  • server/utils/walletExtensionToken.ts
  • src/utils/server.ts

Comment thread server/api/card.ts Outdated
Comment thread server/middleware/auth.ts Outdated
Comment thread src/utils/server.ts Outdated
@aguxez aguxez force-pushed the wallet-extension-auth branch from 81ae104 to e9577a8 Compare June 4, 2026 13:11
@sentry

sentry Bot commented Jun 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.10526% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.60%. Comparing base (698f903) to head (73aa075).
⚠️ Report is 4 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
server/api/card.ts 93.33% 1 Missing and 2 partials ⚠️
server/utils/walletExtension.ts 88.88% 0 Missing and 2 partials ⚠️
src/utils/server.ts 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1070      +/-   ##
==========================================
+ Coverage   72.27%   72.60%   +0.33%     
==========================================
  Files         248      249       +1     
  Lines        9827    10163     +336     
  Branches     3162     3310     +148     
==========================================
+ Hits         7102     7379     +277     
- Misses       2463     2507      +44     
- Partials      262      277      +15     
Flag Coverage Δ
e2e 72.60% <92.10%> (+0.41%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aguxez aguxez marked this pull request as ready for review June 4, 2026 14:17
@aguxez aguxez force-pushed the wallet-extension-auth branch from e9577a8 to efad3c9 Compare June 4, 2026 14:37

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: efad3c91db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/server.ts Outdated
Comment thread server/api/auth/authentication.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9758bffd-2744-4676-a689-11cae77a0c40

📥 Commits

Reviewing files that changed from the base of the PR and between e9577a8 and efad3c9.

📒 Files selected for processing (10)
  • .changeset/brave-otters-serve.md
  • .changeset/clever-ravens-send.md
  • server/api/auth/authentication.ts
  • server/api/card.ts
  • server/middleware/auth.ts
  • server/test/api/auth.test.ts
  • server/test/api/card-wallet-extension.test.ts
  • server/test/middleware/auth-wallet-extension.test.ts
  • server/utils/walletExtensionToken.ts
  • src/utils/server.ts

Comment thread src/utils/server.ts Outdated
@aguxez aguxez force-pushed the wallet-extension-auth branch 3 times, most recently from 44dcd45 to 41ed27e Compare June 4, 2026 16:35
@aguxez aguxez changed the title ✨ app: wallet extensions ✨ server: add auth for wallet extensions Jun 5, 2026
@aguxez aguxez force-pushed the wallet-extension-auth branch 2 times, most recently from abf3473 to 7168e35 Compare June 8, 2026 12:34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/api/card.ts (1)

253-285: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the 401 response to this route contract.

cardAuth() can now return 401 { code: "unauthorized", legacy: "unauthorized" }, but this operation still documents only 200/400/403/404. That leaves the generated OpenAPI out of sync with the new cookie/session/bearer auth behavior.

Suggested contract update
       responses: {
+        401: {
+          description: "Unauthorized",
+          content: {
+            "application/json": {
+              schema: resolver(
+                object({ code: literal("unauthorized"), legacy: literal("unauthorized") }),
+                { errorMode: "ignore" },
+              ),
+            },
+          },
+        },
           description: "Card information",
           content: { "application/json": { schema: resolver(CardResponse, { errorMode: "ignore" }) } },
         },

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bcce92de-2a30-403f-8904-daba2945abd5

📥 Commits

Reviewing files that changed from the base of the PR and between abf3473 and 7168e35.

📒 Files selected for processing (13)
  • .changeset/brave-otters-serve.md
  • .changeset/clever-ravens-send.md
  • server/api/auth/authentication.ts
  • server/api/card.ts
  • server/middleware/cardAuth.ts
  • server/script/openapi.ts
  • server/test/api/auth.test.ts
  • server/test/api/card-better-auth.test.ts
  • server/test/api/card-wallet-extension.test.ts
  • server/test/middleware/cardAuth.test.ts
  • server/test/mocks/auth.ts
  • server/utils/walletExtension.ts
  • src/utils/server.ts

Comment thread server/api/auth/authentication.ts Outdated
Comment thread server/middleware/card-auth.ts Outdated
Comment thread server/test/api/card-better-auth.test.ts Outdated
@aguxez aguxez force-pushed the wallet-extension-auth branch 3 times, most recently from 479f1fc to bf7df95 Compare June 16, 2026 15:29

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf7df95467

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/api/card.ts Outdated
@aguxez aguxez force-pushed the wallet-extension-auth branch from bf7df95 to f801bbf Compare June 16, 2026 16:11

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f801bbf97b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/api/auth/authentication.ts Outdated
Comment thread server/api/card.ts
Comment thread server/api/card.ts Outdated
@aguxez aguxez force-pushed the wallet-extension-auth branch 3 times, most recently from 0e8ae6a to 6511c9d Compare June 17, 2026 09:48
@aguxez aguxez force-pushed the wallet-extension-auth branch 2 times, most recently from 7ce203f to 8f4faed Compare June 24, 2026 10:31

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8f4faedaa6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/utils/walletExtension.ts
Comment thread server/utils/walletExtension.ts
@aguxez aguxez force-pushed the wallet-extension-auth branch from 8f4faed to f5b8840 Compare June 24, 2026 12:07

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5b8840869

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/api/card.ts Outdated
@aguxez aguxez force-pushed the wallet-extension-auth branch from f5b8840 to b81e144 Compare June 24, 2026 12:52
@aguxez

aguxez commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai update the PR's description

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh pr edit 1070 --repo exactly/exa --body "## ✨ Add Auth for Wallet Extensions

### Summary

This PR adds iOS Apple Wallet Extension authentication support to the server, allowing wallet extensions to obtain and use bearer tokens for provisioning access. It also updates the mobile client to send a \`Client-Platform\` header.

---

### Changes

#### Server

**New: Wallet Extension JWT Utilities** (\`server/utils/walletExtension.ts\`)
- \`createToken(credentialId, expires)\`: Signs an HS256 JWT (via \`jose\`) with audience \`\"wallet-extension\"\`, including \`credentialId\` and \`scope: \"card:provisioning\"\`.
- \`verifyToken(token)\`: Verifies the JWT, validates the payload with Valibot, and returns \`{ credentialId, scope }\` or \`null\` on failure.

**Updated: Authentication Endpoint** (\`server/api/auth/authentication.ts\`)
- Accepts an optional \`Client-Platform\` header (\`ios\` | \`android\`).
- On successful SIWE or WebAuthn authentication, if \`platform === \"ios\"\`, returns \`walletExtensionToken\` and \`walletExtensionTokenExpires\` in the response.
- The \`Authentication\` schema now includes optional \`walletExtensionToken?: string\` and \`walletExtensionTokenExpires?: number\` fields.

**New: Card Auth Middleware** (\`server/middleware/cardAuth.ts\`)
- Replaces \`auth()\` on \`GET /api/card\` to support three authentication paths:
  1. **Signed cookie** (\`credential_id\`): reads and attaches \`credentialId\` directly.
  2. **Better Auth session** (\`sessionid\` header): resolves the user's primary or single wallet address to a credential.
  3. **Bearer token** (wallet extension): accepted only when \`scope=provisioning\` is the sole query parameter and no \`sessionid\` header is present; verifies via \`verifyToken\`.
- Returns \`401 { code: \"unauthorized\", legacy: \"unauthorized\" }\` on any auth failure.

**Updated: Card Endpoint** (\`server/api/card.ts\`)
- Uses \`cardAuth()\` middleware instead of \`auth()\`.
- OpenAPI security now includes \`walletExtensionAuth\` alongside \`credentialAuth\` and \`siweAuth\`.
- Documents that wallet-extension bearer access is accepted only when \`scope=provisioning\` is the only scope and \`sessionid\` is absent.

**Updated: OpenAPI Spec** (\`server/script/openapi.ts\`)
- Adds \`walletExtensionAuth\` HTTP bearer security scheme to \`components.securitySchemes\`.

#### Mobile

**Updated: Server Client** (\`src/utils/server.ts\`)
- The \`hc\` fetch override now always builds a \`Headers\` object and unconditionally sets \`Client-Platform\` for \`ios\`/\`android\` platforms before determining mini-app vs. native fetch path.
- Ensures \`Client-Platform\` is included in non-mini-app requests as well.

---

### Tests

| Test file | Coverage |
|-----------|----------|
| \`server/test/api/auth.test.ts\` | iOS WebAuthn/SIWE returns wallet extension token fields; Android omits them; missing header omits them |
| \`server/test/api/card-wallet-extension.test.ts\` | Bearer token grants provisioning access; correct JSON payload; \`getPIN\`/\`getSecrets\` not called |
| \`server/test/api/card-better-auth.test.ts\` | Session-based auth via \`sessionid\` returns full card data |
| \`server/test/middleware/cardAuth.test.ts\` | Cookie, better-auth, and bearer auth paths; all rejection cases (bad scope, expired token, mixed scopes, missing token, etc.) |
| \`server/test/mocks/auth.ts\` | Added \`cardAuth\` mock mirroring \`auth\` mock behavior |

---

### Testing Commands

\`\`\`bash
pnpm nx test:ts server
pnpm nx test:eslint server
pnpm nx test:vi server -- test/api/auth.test.ts test/api/card-wallet-extension.test.ts test/middleware/auth-wallet-extension.test.ts
\`\`\`

---

### Changesets

- \`@exactly/server\`: patch — ✨ add wallet extension auth
- \`@exactly/mobile\`: patch — ✨ send client platform header"

Length of output: 4641


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cat > /tmp/pr_body.md << 'PREOF'
## ✨ Add Auth for Wallet Extensions

### Summary

This PR adds iOS Apple Wallet Extension authentication support to the server, allowing wallet extensions to obtain and use bearer tokens for provisioning access. It also updates the mobile client to send a `Client-Platform` header.

---

### Changes

#### Server

**New: Wallet Extension JWT Utilities** (`server/utils/walletExtension.ts`)
- `createToken(credentialId, expires)`: Signs an HS256 JWT (via `jose`) with audience `"wallet-extension"`, including `credentialId` and `scope: "card:provisioning"`.
- `verifyToken(token)`: Verifies the JWT, validates the payload with Valibot, and returns `{ credentialId, scope }` or `null` on failure.

**Updated: Authentication Endpoint** (`server/api/auth/authentication.ts`)
- Accepts an optional `Client-Platform` header (`ios` | `android`).
- On successful SIWE or WebAuthn authentication, if `platform === "ios"`, returns `walletExtensionToken` and `walletExtensionTokenExpires` in the response.
- The `Authentication` schema now includes optional `walletExtensionToken?: string` and `walletExtensionTokenExpires?: number` fields.

**New: Card Auth Middleware** (`server/middleware/cardAuth.ts`)
- Replaces `auth()` on `GET /api/card` to support three authentication paths:
  1. **Signed cookie** (`credential_id`): reads and attaches `credentialId` directly.
  2. **Better Auth session** (`sessionid` header): resolves the user's primary or single wallet address to a credential.
  3. **Bearer token** (wallet extension): accepted only when `scope=provisioning` is the sole query parameter and no `sessionid` header is present; verifies via `verifyToken`.
- Returns `401 { code: "unauthorized", legacy: "unauthorized" }` on any auth failure.

**Updated: Card Endpoint** (`server/api/card.ts`)
- Uses `cardAuth()` middleware instead of `auth()`.
- OpenAPI security now includes `walletExtensionAuth` alongside `credentialAuth` and `siweAuth`.
- Documents that wallet-extension bearer access is accepted only when `scope=provisioning` is the only scope and `sessionid` is absent.

**Updated: OpenAPI Spec** (`server/script/openapi.ts`)
- Adds `walletExtensionAuth` HTTP bearer security scheme to `components.securitySchemes`.

#### Mobile

**Updated: Server Client** (`src/utils/server.ts`)
- The `hc` fetch override now always builds a `Headers` object and unconditionally sets `Client-Platform` for `ios`/`android` platforms before determining mini-app vs. native fetch path.
- Ensures `Client-Platform` is included in non-mini-app requests as well.

---

### Tests

| Test file | Coverage |
|-----------|----------|
| `server/test/api/auth.test.ts` | iOS WebAuthn/SIWE returns wallet extension token fields; Android omits them; missing header omits them |
| `server/test/api/card-wallet-extension.test.ts` | Bearer token grants provisioning access; correct JSON payload; `getPIN`/`getSecrets` not called |
| `server/test/api/card-better-auth.test.ts` | Session-based auth via `sessionid` returns full card data |
| `server/test/middleware/cardAuth.test.ts` | Cookie, better-auth, and bearer auth paths; all rejection cases (bad scope, expired token, mixed scopes, missing token, etc.) |
| `server/test/mocks/auth.ts` | Added `cardAuth` mock mirroring `auth` mock behavior |

---

### Testing Commands

```bash
pnpm nx test:ts server
pnpm nx test:eslint server
pnpm nx test:vi server -- test/api/auth.test.ts test/api/card-wallet-extension.test.ts test/middleware/auth-wallet-extension.test.ts

Changesets

  • @exactly/server: patch — ✨ add wallet extension auth
  • @exactly/mobile: patch — ✨ send client platform header
    PREOF

gh pr edit 1070 --repo exactly/exa --body-file /tmp/pr_body.md


Length of output: 4163

---



</details>

---

`@aguxez` Unfortunately, the `gh pr edit` command is blocked by workflow restriction settings in this environment, so I wasn't able to update the description automatically. Here's the description you can paste in manually:

---

## ✨ Add Auth for Wallet Extensions

### Summary

This PR adds iOS Apple Wallet Extension authentication support to the server, allowing wallet extensions to obtain and use bearer tokens for provisioning access. It also updates the mobile client to send a `Client-Platform` header.

---

### Changes

#### Server

**New: Wallet Extension JWT Utilities** (`server/utils/walletExtension.ts`)
- `createToken(credentialId, expires)`: Signs an HS256 JWT (via `jose`) with audience `"wallet-extension"`, including `credentialId` and `scope: "card:provisioning"`.
- `verifyToken(token)`: Verifies the JWT, validates the payload with Valibot, and returns `{ credentialId, scope }` or `null` on failure.

**Updated: Authentication Endpoint** (`server/api/auth/authentication.ts`)
- Accepts an optional `Client-Platform` header (`ios` | `android`).
- On successful SIWE or WebAuthn authentication, if `platform === "ios"`, returns `walletExtensionToken` and `walletExtensionTokenExpires` in the response.
- The `Authentication` schema now includes optional `walletExtensionToken?: string` and `walletExtensionTokenExpires?: number` fields.

**New: Card Auth Middleware** (`server/middleware/cardAuth.ts`)
- Replaces `auth()` on `GET /api/card` to support three authentication paths:
  1. **Signed cookie** (`credential_id`): reads and attaches `credentialId` directly.
  2. **Better Auth session** (`sessionid` header): resolves the user's primary or single wallet address to a credential.
  3. **Bearer token** (wallet extension): accepted only when `scope=provisioning` is the sole query parameter and no `sessionid` header is present; verifies via `verifyToken`.
- Returns `401 { code: "unauthorized", legacy: "unauthorized" }` on any auth failure.

**Updated: Card Endpoint** (`server/api/card.ts`)
- Uses `cardAuth()` middleware instead of `auth()`.
- OpenAPI security now includes `walletExtensionAuth` alongside `credentialAuth` and `siweAuth`.
- Documents that wallet-extension bearer access is accepted only when `scope=provisioning` is the only scope and `sessionid` is absent.

**Updated: OpenAPI Spec** (`server/script/openapi.ts`)
- Adds `walletExtensionAuth` HTTP bearer security scheme to `components.securitySchemes`.

#### Mobile

**Updated: Server Client** (`src/utils/server.ts`)
- The `hc` fetch override now always builds a `Headers` object and unconditionally sets `Client-Platform` for `ios`/`android` platforms before determining mini-app vs. native fetch path.
- Ensures `Client-Platform` is included in non-mini-app requests as well.

---

### Tests

| Test file | Coverage |
|-----------|----------|
| `server/test/api/auth.test.ts` | iOS WebAuthn/SIWE returns wallet extension token fields; Android omits them; missing header omits them |
| `server/test/api/card-wallet-extension.test.ts` | Bearer token grants provisioning access; correct JSON payload; `getPIN`/`getSecrets` not called |
| `server/test/api/card-better-auth.test.ts` | Session-based auth via `sessionid` returns full card data |
| `server/test/middleware/cardAuth.test.ts` | Cookie, better-auth, and bearer auth paths; all rejection cases (bad scope, expired token, mixed scopes, missing token, etc.) |
| `server/test/mocks/auth.ts` | Added `cardAuth` mock mirroring `auth` mock behavior |

---

### Testing Commands

```bash
pnpm nx test:ts server
pnpm nx test:eslint server
pnpm nx test:vi server -- test/api/auth.test.ts test/api/card-wallet-extension.test.ts test/middleware/auth-wallet-extension.test.ts

Changesets

  • @exactly/server: patch — ✨ add wallet extension auth
  • @exactly/mobile: patch — ✨ send client platform header

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b81e1446d3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/api/card.ts Outdated
Comment thread server/api/card.ts Outdated
@aguxez aguxez force-pushed the wallet-extension-auth branch 3 times, most recently from e1c5ef3 to 8b803a2 Compare June 25, 2026 10:38

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b803a297a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/api/card.ts Outdated
@aguxez aguxez force-pushed the wallet-extension-auth branch 5 times, most recently from af9225a to 90480b7 Compare June 26, 2026 12:58

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 90480b7c5e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/api/card.ts
@aguxez aguxez force-pushed the wallet-extension-auth branch 2 times, most recently from a151c1e to 9b8fb96 Compare June 26, 2026 14:01
@aguxez aguxez force-pushed the wallet-extension-auth branch from 9b8fb96 to c7efd7a Compare June 29, 2026 08:51
@cruzdanilo cruzdanilo force-pushed the wallet-extension-auth branch from c7efd7a to 73aa075 Compare June 29, 2026 19:07
@cruzdanilo cruzdanilo merged commit 73aa075 into main Jun 29, 2026
10 of 12 checks passed
@cruzdanilo cruzdanilo deleted the wallet-extension-auth branch June 29, 2026 19:32
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.

server: implement new wallet extension endpoint

2 participants