From 54797cd41716bff50424d6a5d3faae86d32a9fcc Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:32:05 -0300 Subject: [PATCH 1/7] Fix JSDocs for `org_permissions` --- .../nextjs/src/server/__tests__/clerkMiddleware.test.ts | 7 +++++++ packages/types/src/jwtv2.ts | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts b/packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts index 9d06d9e10a5..5d2429fb16b 100644 --- a/packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts +++ b/packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts @@ -113,6 +113,13 @@ describe('ClerkMiddleware type tests', () => { clerkMiddlewareMock(); }); + it('prevents usage of system permissions with auth.has()', () => { + clerkMiddlewareMock(async (auth, _event, _request) => { + // @ts-expect-error - system permissions are not allowed + (await auth()).has({ permission: 'org:sys_foo' }); + }); + }); + describe('Multi domain', () => { const defaultProps = { publishableKey: '', secretKey: '' }; diff --git a/packages/types/src/jwtv2.ts b/packages/types/src/jwtv2.ts index 73ef4232f4d..3bd27594f9f 100644 --- a/packages/types/src/jwtv2.ts +++ b/packages/types/src/jwtv2.ts @@ -97,7 +97,7 @@ export interface JwtPayload extends CustomJwtSessionClaims { org_role?: OrganizationCustomRoleKey; /** - * Active organization role + * Active organization permissions */ org_permissions?: OrganizationCustomPermissionKey[]; From d07fb963a85adb0cd7bacd0eae10603b89faed41 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:32:42 -0300 Subject: [PATCH 2/7] Extract system permission prefix to a separate type --- packages/types/src/organizationMembership.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/types/src/organizationMembership.ts b/packages/types/src/organizationMembership.ts index 8a010d19911..3fad5b8a701 100644 --- a/packages/types/src/organizationMembership.ts +++ b/packages/types/src/organizationMembership.ts @@ -68,13 +68,15 @@ export type OrganizationCustomRoleKey = ClerkAuthorization extends Placeholder : Base['role'] : Base['role']; +export type OrganizationSystemPermissionPrefix = 'org:sys_'; + export type OrganizationSystemPermissionKey = - | 'org:sys_domains:manage' - | 'org:sys_profile:manage' - | 'org:sys_profile:delete' - | 'org:sys_memberships:read' - | 'org:sys_memberships:manage' - | 'org:sys_domains:read'; + | `${OrganizationSystemPermissionPrefix}domains:manage` + | `${OrganizationSystemPermissionPrefix}profile:manage` + | `${OrganizationSystemPermissionPrefix}profile:delete` + | `${OrganizationSystemPermissionPrefix}memberships:read` + | `${OrganizationSystemPermissionPrefix}memberships:manage` + | `${OrganizationSystemPermissionPrefix}domains:read`; /** * OrganizationPermissionKey is a combination of system and custom permissions. From c3e62351df87dfdb4db5409613e83c82b9e01514 Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:43:34 -0300 Subject: [PATCH 3/7] Add type guard from session claims --- packages/backend/src/tokens/authObjects.ts | 6 ++--- packages/types/src/organizationMembership.ts | 1 - packages/types/src/session.ts | 24 ++++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/tokens/authObjects.ts b/packages/backend/src/tokens/authObjects.ts index e24df5830c6..a0b967cb4df 100644 --- a/packages/backend/src/tokens/authObjects.ts +++ b/packages/backend/src/tokens/authObjects.ts @@ -1,7 +1,7 @@ import { createCheckAuthorization } from '@clerk/shared/authorization'; import type { ActClaim, - CheckAuthorizationWithCustomPermissions, + CheckAuthorizationFromSessionClaims, JwtPayload, OrganizationCustomPermissionKey, OrganizationCustomRoleKey, @@ -42,7 +42,7 @@ export type SignedInAuthObject = { */ factorVerificationAge: [number, number] | null; getToken: ServerGetToken; - has: CheckAuthorizationWithCustomPermissions; + has: CheckAuthorizationFromSessionClaims; debug: AuthObjectDebug; }; @@ -65,7 +65,7 @@ export type SignedOutAuthObject = { */ factorVerificationAge: null; getToken: ServerGetToken; - has: CheckAuthorizationWithCustomPermissions; + has: CheckAuthorizationFromSessionClaims; debug: AuthObjectDebug; }; diff --git a/packages/types/src/organizationMembership.ts b/packages/types/src/organizationMembership.ts index 3fad5b8a701..93cf0be204c 100644 --- a/packages/types/src/organizationMembership.ts +++ b/packages/types/src/organizationMembership.ts @@ -69,7 +69,6 @@ export type OrganizationCustomRoleKey = ClerkAuthorization extends Placeholder : Base['role']; export type OrganizationSystemPermissionPrefix = 'org:sys_'; - export type OrganizationSystemPermissionKey = | `${OrganizationSystemPermissionPrefix}domains:manage` | `${OrganizationSystemPermissionPrefix}profile:manage` diff --git a/packages/types/src/session.ts b/packages/types/src/session.ts index 028ceacee31..f62bf0d317e 100644 --- a/packages/types/src/session.ts +++ b/packages/types/src/session.ts @@ -15,6 +15,7 @@ import type { OrganizationCustomPermissionKey, OrganizationCustomRoleKey, OrganizationPermissionKey, + OrganizationSystemPermissionPrefix, } from './organizationMembership'; import type { ClerkResource } from './resource'; import type { @@ -25,6 +26,29 @@ import type { import type { TokenResource } from './token'; import type { UserResource } from './user'; +type DisallowSystemPermissions
= P extends `${OrganizationSystemPermissionPrefix}${string}` + ? 'System permissions are not included in session claims and cannot be used on the server-side' + : P; + +/** + * Type guard for server-side authorization checks using session claims. + * System permissions are not allowed since they are not included + * in session claims and cannot be verified on the server side. + */ +export type CheckAuthorizationFromSessionClaims =
( + isAuthorizedParams: WithReverification< + | { + role: OrganizationCustomRoleKey; + permission?: never; + } + | { + role?: never; + permission: DisallowSystemPermissions
;
+ }
+ | { role?: never; permission?: never }
+ >,
+) => boolean;
+
export type CheckAuthorizationFn (
+ params?: CheckAuthorizationParamsFromSessionClaims ,
+ options?: AuthProtectOptions,
+ ): Promise = P extends `${OrganizationSyst
? 'System permissions are not included in session claims and cannot be used on the server-side'
: P;
-/**
- * Type guard for server-side authorization checks using session claims.
- * System permissions are not allowed since they are not included
- * in session claims and cannot be verified on the server side.
- */
-export type CheckAuthorizationFromSessionClaims = (
- isAuthorizedParams: WithReverification<
- | {
- role: OrganizationCustomRoleKey;
- permission?: never;
- }
- | {
- role?: never;
- permission: DisallowSystemPermissions ;
- }
- | { role?: never; permission?: never }
- >,
-) => boolean;
-
export type CheckAuthorizationFn (
+ isAuthorizedParams: CheckAuthorizationParamsFromSessionClaims ,
+) => boolean;
+
+export type CheckAuthorizationParamsFromSessionClaims = WithReverification<
+ | {
+ role: OrganizationCustomRoleKey;
+ permission?: never;
+ }
+ | {
+ role?: never;
+ permission: DisallowSystemPermissions ;
+ }
+ | { role?: never; permission?: never }
+>;
+
export interface SessionResource extends ClerkResource {
id: string;
status: SessionStatus;
From afad6c9fa315eed4909458495df7ecd9961cc675 Mon Sep 17 00:00:00 2001
From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com>
Date: Tue, 7 Jan 2025 10:33:46 -0300
Subject: [PATCH 7/7] Include `@clerk/nextjs` on changeset
---
.changeset/fair-bobcats-pull.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/.changeset/fair-bobcats-pull.md b/.changeset/fair-bobcats-pull.md
index aa766d61040..8ae6aac38d3 100644
--- a/.changeset/fair-bobcats-pull.md
+++ b/.changeset/fair-bobcats-pull.md
@@ -1,6 +1,7 @@
---
'@clerk/backend': patch
'@clerk/types': patch
+'@clerk/nextjs': patch
---
Add type-level validation to prevent server-side usage of system permissions