Skip to content

fix(cli): jwt errors#5862

Open
7ttp wants to merge 7 commits into
supabase:developfrom
7ttp:fix/cli-side-err
Open

fix(cli): jwt errors#5862
7ttp wants to merge 7 commits into
supabase:developfrom
7ttp:fix/cli-side-err

Conversation

@7ttp

@7ttp 7ttp commented Jul 11, 2026

Copy link
Copy Markdown
Member

@7ttp
7ttp requested a review from a team as a code owner July 11, 2026 14:33
@github-actions

Copy link
Copy Markdown
Contributor

👋 Thanks! The linked issue hasn't been marked open-for-contribution yet, so this pull request is being closed automatically.

A maintainer adds that label once an issue is triaged and ready to be worked on. Please wait for the label before opening a pull request.
See CONTRIBUTING.md for the full workflow. Once a maintainer adds the open-for-contribution label to a linked open issue, reopen or open a new pull request and it will be accepted.

@github-actions github-actions Bot closed this Jul 11, 2026
@7ttp 7ttp reopened this Jul 11, 2026
@7ttp 7ttp self-assigned this Jul 11, 2026
@7ttp

7ttp commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 3da2ad9d1c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@7ttp

7ttp commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

👋 Thanks! The linked issue hasn't been marked open-for-contribution yet, so this pull request is being closed automatically.

A maintainer adds that label once an issue is triaged and ready to be worked on. Please wait for the label before opening a pull request. See CONTRIBUTING.md for the full workflow. Once a maintainer adds the open-for-contribution label to a linked open issue, reopen or open a new pull request and it will be accepted.

imo this shouldn't really happen for the members ? 😅

thoughts @avallete @jgoux ?

@avallete avallete added open-for-contribution Open for contribution allow any external user to submit a PR fixing this issue and removed open-for-contribution Open for contribution allow any external user to submit a PR fixing this issue labels Jul 12, 2026
@avallete

Copy link
Copy Markdown
Member

👋 Thanks! The linked issue hasn't been marked open-for-contribution yet, so this pull request is being closed automatically.
A maintainer adds that label once an issue is triaged and ready to be worked on. Please wait for the label before opening a pull request. See CONTRIBUTING.md for the full workflow. Once a maintainer adds the open-for-contribution label to a linked open issue, reopen or open a new pull request and it will be accepted.

imo this shouldn't really happen for the members ? 😅

thoughts @avallete @jgoux ?

It shouldn't, sadly if your affiliation is "private" on https://github.com/orgs/supabase/people
Then, since the GH token for the check is a public one, that won't be detected by the action. Then, the fallback is to look for active repo permissions (some admin are private members) but that doesn't apply in your case either 😅

If that's not a bother, could you try to your supabase membership to "public" ? This should allows your PR's to pass the gate without issues.

@avallete avallete left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this might actually be a BC need to double check.

@avallete

avallete commented Jul 13, 2026

Copy link
Copy Markdown
Member

Alright, tell me if I'm mistaken @kallebysantos @7ttp but the Hosted platform does not uses { error } at all does they ?

Looking at the code, I think this is the wrong fix, and we actually need a contract between edge-functions/stdio/cli for error codes, they seems to solely rely on { code, message } shape. This seems to introduce one more schema rather than align with platform:

   Runtime                     JWT error body
  ━━━━━━━━━━━━━━━━━━━━━━━━━━  ━━━━━━━━━━━━━━━━━━━
   Hosted platform             { code, message }
  ──────────────────────────  ───────────────────
   Stable local CLI today      { msg }
  ──────────────────────────  ───────────────────
   PR #5862                    { error }
  ──────────────────────────  ───────────────────
   Next/alpha local stack      { msg }
  ──────────────────────────  ───────────────────
   Self-hosted Docker today    { msg }

The official docs shows "error, message" contract: https://github.com/supabase/supabase/blob/master/apps/docs/content/troubleshooting/edge-function-401-error-response.mdx

And it look like the only place where we rely on error in studio is there: https://github.com/supabase/supabase/blob/master/apps/studio/pages/api/edge-functions/test.ts#L95-L100

I think we should standardize toward { code, message } instead of adding another contract ?
I think the root cause of the issue is in studio:

flowchart LR
    UI["Studio Test UI"]
    SP["Studio test proxy<br/>currently assumes body.error"]
    GW["Gateway<br/>Kong / Envoy / hosted router"]
    JW["JWT admission layer<br/>hosted ingress / local main worker"]
    UF["User function"]

    UI --> SP --> GW --> JW --> UF

    GW -. "503: {message} or text" .-> SP
    JW -. "401: hosted {code,message}<br/>local legacy {msg}" .-> SP
    UF -. "arbitrary status/body/headers" .-> SP
Loading

The bug I think is https://github.com/supabase/supabase/blob/master/apps/studio/pages/api/edge-functions/test.ts#L92-L107 :

  1. It receives a legitimate non-2xx response.
  2. It discards the body and headers.
  3. It tries only errorBody.error.
  4. Everything else becomes “Edge function returned an error.”

That assumption is impossible to satisfy universally:

I think a minimal cleaner fix:

I would make the Studio test endpoint a transparent response adapter.

A completed upstream request even if it returns 401, 404, or 503 is a successful execution of the test operation. It should return:

{
  status: upstream.status,
  headers: upstreamHeaders,
  body: upstreamBody
}

The Studio proxy itself should return HTTP 200 for that envelope. Reserve proxy-level 4xx/5xx for cases where Studio could not execute the test at all: invalid URL, network failure, malformed request, etc.

Concretely, in supabase/apps/studio/pages/api/edge-functions/test.ts:

  • always use await response.text() do not parse and reserialize based on Content-Type.
  • always collect upstream headers.
  • remove the special !response.ok schema extraction.
  • return the same {status, headers, body} envelope for every upstream status.

This fits the existing architecture unusually well:

#47855 (https://github.com/supabase/supabase/pull/47855)’s tolerant extractor is an acceptable hotfix, but it remains schema guessing and still loses response headers and structured bodies. Transparent relay is cleaner.

Tests should cover hosted {code,message}, Kong {message}, legacy {msg}, nested JSON, arbitrary JSON, plain text, invalid JSON, headers, and a genuine fetch exception.

Where JWT mirror code should live

JWT errors belong at the layer that performs JWT admission not in Studio and not in the generic Edge Runtime engine.

The canonical contract should be the hosted ingress contract:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
sb-error-code: UNAUTHORIZED_NO_AUTH_HEADER

{
  "code": "UNAUTHORIZED_NO_AUTH_HEADER",
  "message": "Missing authorization header"
}

Canonical codes:

  • UNAUTHORIZED_NO_AUTH_HEADER
  • UNAUTHORIZED_INVALID_JWT_FORMAT
  • UNAUTHORIZED_LEGACY_JWT
  • UNAUTHORIZED_ASYMMETRIC_JWT
  • UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM

The mirrors should live beside JWT verification in each independently shipped bootstrap:

  • Hosted authority: edge-functions-ingress/src/main/errors.ts, jwt.ts, and utils.ts.
  • Self-hosted Docker: supabase/docker/volumes/functions/main/index.ts.
  • Stable CLI runtime: cli/apps/cli/src/shared/functions/serve.main.ts.
  • Next/alpha CLI runtime: cli/packages/stack/src/services/edge-runtime-main.ts.

Each bootstrap should have a small local JwtFailure mapping and one unauthorized(failure) response helper.

Backward-compatible migration

Local {msg} has shipped since 2023, so replace it additively:

{
  "code": "UNAUTHORIZED_INVALID_JWT_FORMAT",
  "message": "Invalid JWT format",
  "msg": "Invalid JWT format"
}

Also emit sb-error-code. Treat msg as deprecated and remove it only in an explicit major-version change or keep the tiny alias indefinitely.

Recommended sequence:

  1. Fix Studio to preserve arbitrary upstream responses.
  2. Add canonical {code,message} and sb-error-code to all JWT admission bootstraps.
  3. Keep legacy msg during migration.
  4. Add identical response-contract tests in self-hosted, stable CLI, and next CLI.
  5. Re-scope fix(cli): jwt errors #5862 away from msg → error, to {code,message} it currently also misses the next CLI path.

The important boundary is to standardize all Supabase-owned JWT errors, preserve all other HTTP responses transparently.

Trying to standardize gateway failures and user-function responses would require rewriting responses that Supabase does not own.

cc @SaxonF @joshenlim since it seems you authored: https://github.com/supabase/supabase/blame/master/apps/studio/pages/api/edge-functions/test.ts#L92-L107 would you give it a look, tell me if you think I'm off ?

@kallebysantos

kallebysantos commented Jul 13, 2026

Copy link
Copy Markdown
Member

You're right... I missed it, and I agree that we should use a single pattern across all environments.
As addition to @avallete comment: https://supabase.com/docs/guides/functions/error-codes

We've been refactoring Platform error codes, and yes! we're now using {code, message} object, example:

export enum AuthErrors {
  UnsupportedTokenAlgorithm = 'UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM',
  MissingAuthHeader = 'UNAUTHORIZED_NO_AUTH_HEADER',
  // ....
}
// in case JWT validation fails:
const error = {
    code: AuthErrors.UnsupportedTokenAlgorithm,
    message: `Unsupported JWT algorithm ${jwt.alg}`
}

return Response.json(error, { 
  status:  Status.Unauthorized,
  headers: {
    'sb-error-code': AuthErrors.UnsupportedTokenAlgorithm
  }
})

@7ttp
7ttp force-pushed the fix/cli-side-err branch 2 times, most recently from 2af6b28 to fd9e5a1 Compare July 13, 2026 15:46
@7ttp
7ttp marked this pull request as draft July 13, 2026 15:48

@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: fd9e5a1a7d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/cli/src/shared/functions/serve.main.ts Outdated
Comment thread apps/cli/src/shared/functions/serve.main.ts Outdated
@7ttp
7ttp force-pushed the fix/cli-side-err branch from fd9e5a1 to 921984a Compare July 13, 2026 17:26
@7ttp
7ttp marked this pull request as ready for review July 13, 2026 17:30

@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: 921984a8e4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/cli/src/shared/functions/serve.main.ts
@7ttp

7ttp commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

@codex review

@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: 7cfdaeed5a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/cli/src/shared/functions/serve.main.ts
@7ttp

7ttp commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

mb! @avallete @kallebysantos

I’ve rescoped this PR to the { code, message } pattern (kept msg for now for BC)

but b4 this will patch the studio test proxy so it preserves the upstream status, headers, and body instead of keying only off errorBody.error (waiting for the team's take on it)

@avallete

Copy link
Copy Markdown
Member
  • PR does not yet resolve/close Edge function JWT verification errors return { msg } instead of { error } in serve.main.ts #5861. The response intentionally uses { code, message, msg }, not error (source (
    function getAuthErrorResponse({ code, message }: AuthFailure) {
    return getResponse({ code, message, msg: message }, STATUS_CODE.Unauthorized, {
    "sb-error-code": code,
    });
    }
    )). That aligns with the platform contract, but Studio still reads error, both Studio fixes remain open. Merge one first, or change Closes Edge function JWT verification errors return { msg } instead of { error } in serve.main.ts #5861 and update the stale PR description, which still claims this adds error.
  • P2 - next/alpha local runtime remains inconsistent. packages/stack/src/services/edge-runtime-main.ts:63 still returns only { msg }, supabase functions dev therefore lacks { code, message } and sb-error-code.
  • P2 - no behavioral coverage. Five externally visible JWT classifications were added without tests asserting status, body, or sb-error-code. Existing tests only cover bundling, artifact drift, and offline startup. Add focused contract cases for missing/malformed auth, invalid HS256/asymmetric JWTs, and unsupported algorithms.

@7ttp
7ttp force-pushed the fix/cli-side-err branch from 97b1e25 to f740e0c Compare July 16, 2026 22:18

@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: f740e0c8ab

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/stack/src/services/edge-runtime-main.ts Outdated

@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: 1ca5d7793e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/cli/src/shared/functions/serve.main.ts
Comment thread packages/stack/src/services/edge-runtime-main.ts
@7ttp

7ttp commented Jul 16, 2026

Copy link
Copy Markdown
Member Author
  • PR does not yet resolve/close Edge function JWT verification errors return { msg } instead of { error } in serve.main.ts #5861. The response intentionally uses { code, message, msg }, not error (source (
    function getAuthErrorResponse({ code, message }: AuthFailure) {
    return getResponse({ code, message, msg: message }, STATUS_CODE.Unauthorized, {
    "sb-error-code": code,
    });
    }

    )). That aligns with the platform contract, but Studio still reads error, both Studio fixes remain open. Merge one first, or change Closes Edge function JWT verification errors return { msg } instead of { error } in serve.main.ts #5861 and update the stale PR description, which still claims this adds error.
  • P2 - next/alpha local runtime remains inconsistent. packages/stack/src/services/edge-runtime-main.ts:63 still returns only { msg }, supabase functions dev therefore lacks { code, message } and sb-error-code.
  • P2 - no behavioral coverage. Five externally visible JWT classifications were added without tests asserting status, body, or sb-error-code. Existing tests only cover bundling, artifact drift, and offline startup. Add focused contract cases for missing/malformed auth, invalid HS256/asymmetric JWTs, and unsupported algorithms.

Thanks! 💚 Addressed all three: updated the desc and left #5861 related/pending

& also aligned the next runtime, added behavioral coverage around it...

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.

3 participants