Skip to content

fix(shared): Throw error on unknown scopes#7754

Open
dstaley wants to merge 2 commits intomainfrom
ds.fix/feature-scope
Open

fix(shared): Throw error on unknown scopes#7754
dstaley wants to merge 2 commits intomainfrom
ds.fix/feature-scope

Conversation

@dstaley
Copy link
Member

@dstaley dstaley commented Feb 3, 2026

Description

This PR updates our parsing of the features claim and related functions to throw an error when provided with an invalid scope.

Previously, the following check would return true for the fea claim of u:featurename:

has({ feature: 'unknownscope:featurename' })

This is because the previous implementation would simply drop any unknown scope. This became confusing because the following would also return true:

has({ feature: 'organization:featurename' })

This is because organization is not the scope for an organization feature; it's org.

With the new parser, you're able to use any of the following scopes: u, user, o, org, organization.

This PR also optimizes the splitScope function to be a bit more performant since it was doing lots of redundant maps and filters.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • Breaking Changes

    • Major version bump for the shared library.
    • Feature and plan checks now strictly validate explicit scopes and will throw on invalid/unknown scopes.
  • New Features

    • Explicit scope support for feature resolution, enabling organization- or user-level authorization and more precise parsing.
  • Tests

    • Added comprehensive authorization tests covering scope parsing, error handling, and feature resolution.

@changeset-bot
Copy link

changeset-bot bot commented Feb 3, 2026

🦋 Changeset detected

Latest commit: 2cf4786

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

This PR includes changesets to release 20 packages
Name Type
@clerk/shared Major
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/backend Patch
@clerk/chrome-extension Patch
@clerk/clerk-js Patch
@clerk/expo-passkeys Patch
@clerk/expo Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/localizations Patch
@clerk/msw Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/react Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/ui Patch
@clerk/vue 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

@vercel
Copy link

vercel bot commented Feb 3, 2026

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Feb 4, 2026 6:02pm

Request Review

@dstaley dstaley requested a review from mzhong9723 February 3, 2026 22:12
@github-actions github-actions bot added the core-3 label Feb 3, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 3, 2026

📝 Walkthrough

Walkthrough

Adds a changeset declaring a major version bump for @clerk/shared, new unit tests for authorization parsing and error cases, and updates the authorization implementation. Introduces ORG_SCOPES and USER_SCOPES, enforces explicit-scope validation (throws on unknown scopes), routes feature/plan checks to org or user feature sets when scoped, falls back to merged checks when not scoped, and reworks splitByScope to return separated org and user arrays and to throw on malformed claim pieces.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(shared): Throw error on unknown scopes' directly and concisely summarizes the main change: stricter scope validation in authorization logic that now throws errors for invalid scopes instead of silently dropping them.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 3, 2026

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7754

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7754

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7754

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7754

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7754

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7754

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7754

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7754

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7754

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7754

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7754

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7754

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7754

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7754

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7754

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7754

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7754

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7754

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7754

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7754

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7754

commit: 2cf4786

@dstaley
Copy link
Member Author

dstaley commented Feb 3, 2026

!allow-major

@dstaley dstaley closed this Feb 3, 2026
@dstaley dstaley reopened this Feb 3, 2026
@@ -127,13 +139,29 @@ const checkBillingAuthorization: CheckBillingAuthorization = (params, options) =
};

const splitByScope = (fea: string | null | undefined) => {
Copy link
Member

Choose a reason for hiding this comment

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

This got flagged by Codex

splitByScope edge case: missing :

In the new loop, it does:
• const colonIndex = part.indexOf(':')
• then slices using that index. 

If a segment ever lacks : (or is malformed), colonIndex becomes -1, and the slicing behavior gets weird (scope becomes part.slice(0, -1) and value becomes the entire string). Today the features claim may always be well-formed, but this helper is the kind of thing that gets reused and then surprises someone later.

Suggestion: guard early:
• if colonIndex <= 0 (or === -1) → continue (or treat as invalid and throw, depending on how strict you want claims parsing to be).
• also consider trimming out empty value.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a check! These are from FAPI so they're likely always well-formed, but it doesn't hurt to at least throw an error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants