From f9d1bc758972328be7ddb7d61f66baea2aaf2c96 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 6 Nov 2023 14:04:59 +0200 Subject: [PATCH] feat(nextjs,clerk-react,types,clerk-js): Add experimental support for `` (#1942) (#2051) * feat(nextjs,clerk-react,types,clerk-js): Add experimental support for `` * chore(clerk-js): Remove references to permissions * fix(clerk-js): Edit internal Gate to use some instead of any * chore(clerk-js): Enable tests * chore(clerk-js): Add changeset * chore(types): Create experimental types * feat(nextjs): Export `` * chore(chrome-extension): Update snapshot --- .changeset/orange-pumpkins-poke.md | 10 +++ packages/backend/src/tokens/authObjects.ts | 60 +++++++++++++++- .../src/__snapshots__/exports.test.ts.snap | 1 + .../src/core/resources/Session.test.ts | 4 +- .../clerk-js/src/core/resources/Session.ts | 72 +++++++++---------- packages/clerk-js/src/ui/common/Gate.tsx | 10 ++- .../OrganizationProfileRoutes.tsx | 2 +- .../clerk-js/src/ui/utils/test/mockHelpers.ts | 2 +- .../app-router/server/controlComponents.tsx | 37 ++++++++++ .../src/client-boundary/controlComponents.ts | 1 + packages/nextjs/src/components.client.ts | 2 +- packages/nextjs/src/components.server.ts | 5 +- packages/nextjs/src/index.ts | 6 ++ .../src/components/controlComponents.tsx | 22 +++++- packages/react/src/components/index.ts | 1 + packages/react/src/hooks/useAuth.ts | 50 ++++++++++++- packages/react/src/utils/deriveState.ts | 8 ++- packages/types/src/jwtv2.ts | 1 + packages/types/src/session.ts | 30 +++++--- 19 files changed, 257 insertions(+), 67 deletions(-) create mode 100644 .changeset/orange-pumpkins-poke.md diff --git a/.changeset/orange-pumpkins-poke.md b/.changeset/orange-pumpkins-poke.md new file mode 100644 index 0000000000..6673bf5dc0 --- /dev/null +++ b/.changeset/orange-pumpkins-poke.md @@ -0,0 +1,10 @@ +--- +'@clerk/chrome-extension': minor +'@clerk/clerk-js': minor +'@clerk/backend': minor +'@clerk/nextjs': minor +'@clerk/clerk-react': minor +'@clerk/types': minor +--- + +Experimental support for `` with role checks. diff --git a/packages/backend/src/tokens/authObjects.ts b/packages/backend/src/tokens/authObjects.ts index 3bb5b5bbf2..c9096b6b85 100644 --- a/packages/backend/src/tokens/authObjects.ts +++ b/packages/backend/src/tokens/authObjects.ts @@ -1,5 +1,11 @@ import { deprecated } from '@clerk/shared/deprecated'; -import type { ActClaim, JwtPayload, ServerGetToken, ServerGetTokenOptions } from '@clerk/types'; +import type { + ActClaim, + experimental__CheckAuthorizationWithoutPermission, + JwtPayload, + ServerGetToken, + ServerGetTokenOptions, +} from '@clerk/types'; import type { Organization, Session, User } from '../api'; import { createBackendApiClient } from '../api'; @@ -36,6 +42,10 @@ export type SignedInAuthObject = { orgSlug: string | undefined; organization: Organization | undefined; getToken: ServerGetToken; + /** + * @experimental The method is experimental and subject to change in future releases. + */ + experimental__has: experimental__CheckAuthorizationWithoutPermission; debug: AuthObjectDebug; }; @@ -51,6 +61,10 @@ export type SignedOutAuthObject = { orgSlug: null; organization: null; getToken: ServerGetToken; + /** + * @experimental The method is experimental and subject to change in future releases. + */ + experimental__has: experimental__CheckAuthorizationWithoutPermission; debug: AuthObjectDebug; }; @@ -110,6 +124,7 @@ export function signedInAuthObject( orgSlug, organization, getToken, + experimental__has: createHasAuthorization({ orgId, orgRole, userId }), debug: createDebug({ ...options, ...debugData }), }; } @@ -131,11 +146,21 @@ export function signedOutAuthObject(debugData?: AuthObjectDebugData): SignedOutA orgSlug: null, organization: null, getToken: () => Promise.resolve(null), + experimental__has: () => false, debug: createDebug(debugData), }; } -export function prunePrivateMetadata(resource?: { private_metadata: any } | { privateMetadata: any } | null) { +export function prunePrivateMetadata( + resource?: + | { + private_metadata: any; + } + | { + privateMetadata: any; + } + | null, +) { // Delete sensitive private metadata from resource before rendering in SSR if (resource) { // @ts-ignore @@ -190,3 +215,34 @@ const createGetToken: CreateGetToken = params => { return sessionToken; }; }; + +const createHasAuthorization = + ({ + orgId, + orgRole, + userId, + }: { + userId: string; + orgId: string | undefined; + orgRole: string | undefined; + }): experimental__CheckAuthorizationWithoutPermission => + params => { + if (!orgId || !userId) { + return false; + } + + if (params.role) { + return orgRole === params.role; + } + + if (params.some) { + return !!params.some.find(permObj => { + if (permObj.role) { + return orgRole === permObj.role; + } + return false; + }); + } + + return false; + }; diff --git a/packages/chrome-extension/src/__snapshots__/exports.test.ts.snap b/packages/chrome-extension/src/__snapshots__/exports.test.ts.snap index 2d7332aaf8..3ac0e70526 100644 --- a/packages/chrome-extension/src/__snapshots__/exports.test.ts.snap +++ b/packages/chrome-extension/src/__snapshots__/exports.test.ts.snap @@ -8,6 +8,7 @@ exports[`public exports should not include a breaking change 1`] = ` "ClerkProvider", "CreateOrganization", "EmailLinkErrorCode", + "Experimental__Gate", "MagicLinkErrorCode", "MultisessionAppSupport", "OrganizationList", diff --git a/packages/clerk-js/src/core/resources/Session.test.ts b/packages/clerk-js/src/core/resources/Session.test.ts index e098f5597d..b3f5c889d8 100644 --- a/packages/clerk-js/src/core/resources/Session.test.ts +++ b/packages/clerk-js/src/core/resources/Session.test.ts @@ -73,7 +73,7 @@ describe('Session', () => { updated_at: new Date().getTime(), } as SessionJSON); - const isAuthorized = await session.isAuthorized({ permission: 'org:sys_profile:delete' }); + const isAuthorized = await session.experimental__checkAuthorization({ permission: 'org:sys_profile:delete' }); expect(isAuthorized).toBe(true); }); @@ -93,7 +93,7 @@ describe('Session', () => { updated_at: new Date().getTime(), } as SessionJSON); - const isAuthorized = await session.isAuthorized({ permission: 'org:sys_profile:delete' }); + const isAuthorized = await session.experimental__checkAuthorization({ permission: 'org:sys_profile:delete' }); expect(isAuthorized).toBe(false); }); diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index a7850e8000..ef04429b66 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -2,9 +2,9 @@ import { runWithExponentialBackOff } from '@clerk/shared'; import { is4xxError } from '@clerk/shared/error'; import type { ActJWTClaim, + CheckAuthorization, GetToken, GetTokenOptions, - IsAuthorized, SessionJSON, SessionResource, SessionStatus, @@ -70,8 +70,6 @@ export class Session extends BaseResource implements SessionResource { return SessionTokenCache.clear(); }; - // TODO: Fix this eslint error - // eslint-disable-next-line @typescript-eslint/require-await getToken: GetToken = async (options?: GetTokenOptions): Promise => { return runWithExponentialBackOff(() => this._getToken(options), { shouldRetry: (error: unknown, currentIteration: number) => !is4xxError(error) && currentIteration < 4, @@ -81,48 +79,44 @@ export class Session extends BaseResource implements SessionResource { /** * @experimental The method is experimental and subject to change in future releases. */ - isAuthorized: IsAuthorized = async params => { - return new Promise((resolve, reject) => { - // if there is no active organization user can not be authorized - if (!this.lastActiveOrganizationId || !this.user) { - return resolve(false); - } + experimental__checkAuthorization: CheckAuthorization = params => { + // if there is no active organization user can not be authorized + if (!this.lastActiveOrganizationId || !this.user) { + return false; + } - // loop through organizationMemberships from client piggybacking - const orgMemberships = this.user.organizationMemberships || []; - const activeMembership = orgMemberships.find(mem => mem.organization.id === this.lastActiveOrganizationId); + // loop through organizationMemberships from client piggybacking + const orgMemberships = this.user.organizationMemberships || []; + const activeMembership = orgMemberships.find(mem => mem.organization.id === this.lastActiveOrganizationId); - // Based on FAPI this should never happen, but we handle it anyway - if (!activeMembership) { - return resolve(false); - } + // Based on FAPI this should never happen, but we handle it anyway + if (!activeMembership) { + return false; + } - const activeOrganizationPermissions = activeMembership.permissions; - const activeOrganizationRole = activeMembership.role; + const activeOrganizationPermissions = activeMembership.permissions; + const activeOrganizationRole = activeMembership.role; - if (params.permission) { - return resolve(activeOrganizationPermissions.includes(params.permission)); - } - if (params.role) { - return resolve(activeOrganizationRole === params.role); - } + if (params.permission) { + return activeOrganizationPermissions.includes(params.permission); + } + if (params.role) { + return activeOrganizationRole === params.role; + } - if (params.any) { - return resolve( - !!params.any.find(permObj => { - if (permObj.permission) { - return activeOrganizationPermissions.includes(permObj.permission); - } - if (permObj.role) { - return activeOrganizationRole === permObj.role; - } - return false; - }), - ); - } + if (params.some) { + return !!params.some.find(permObj => { + if (permObj.permission) { + return activeOrganizationPermissions.includes(permObj.permission); + } + if (permObj.role) { + return activeOrganizationRole === permObj.role; + } + return false; + }); + } - return reject(); - }); + return false; }; #hydrateCache = (token: TokenResource | null) => { diff --git a/packages/clerk-js/src/ui/common/Gate.tsx b/packages/clerk-js/src/ui/common/Gate.tsx index 7da69f6b22..0c1a016742 100644 --- a/packages/clerk-js/src/ui/common/Gate.tsx +++ b/packages/clerk-js/src/ui/common/Gate.tsx @@ -1,12 +1,11 @@ -import type { IsAuthorized } from '@clerk/types'; +import type { CheckAuthorization } from '@clerk/types'; import type { ComponentType, PropsWithChildren, ReactNode } from 'react'; import React, { useEffect } from 'react'; import { useCoreSession } from '../contexts'; -import { useFetch } from '../hooks'; import { useRouter } from '../router'; -type GateParams = Parameters[0]; +type GateParams = Parameters[0]; type GateProps = PropsWithChildren< GateParams & { fallback?: ReactNode; @@ -15,11 +14,10 @@ type GateProps = PropsWithChildren< >; export const useGate = (params: GateParams) => { - const { isAuthorized } = useCoreSession(); - const { data: isAuthorizedUser } = useFetch(isAuthorized, params); + const { experimental__checkAuthorization } = useCoreSession(); return { - isAuthorizedUser, + isAuthorizedUser: experimental__checkAuthorization(params), }; }; diff --git a/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx b/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx index 53fd277bfb..0af1a3cd55 100644 --- a/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx @@ -77,7 +77,7 @@ export const OrganizationProfileRoutes = (props: PropsOfComponent diff --git a/packages/clerk-js/src/ui/utils/test/mockHelpers.ts b/packages/clerk-js/src/ui/utils/test/mockHelpers.ts index e8dc6477cd..bb03f1628a 100644 --- a/packages/clerk-js/src/ui/utils/test/mockHelpers.ts +++ b/packages/clerk-js/src/ui/utils/test/mockHelpers.ts @@ -35,7 +35,7 @@ export const mockClerkMethods = (clerk: LoadedClerk): DeepJestMocked { mockMethodsOf(session, { - exclude: ['isAuthorized'], + exclude: ['experimental__checkAuthorization'], }); mockMethodsOf(session.user); session.user?.emailAddresses.forEach(m => mockMethodsOf(m)); diff --git a/packages/nextjs/src/app-router/server/controlComponents.tsx b/packages/nextjs/src/app-router/server/controlComponents.tsx index ee3aceacae..ac506a1ec8 100644 --- a/packages/nextjs/src/app-router/server/controlComponents.tsx +++ b/packages/nextjs/src/app-router/server/controlComponents.tsx @@ -1,3 +1,5 @@ +import type { experimental__CheckAuthorizationWithoutPermission } from '@clerk/types'; +import { redirect } from 'next/navigation'; import React from 'react'; import { auth } from './auth'; @@ -13,3 +15,38 @@ export function SignedOut(props: React.PropsWithChildren) { const { userId } = auth(); return userId ? null : <>{children}; } + +type GateServerComponentProps = React.PropsWithChildren< + Parameters[0] & { + fallback?: React.ReactNode; + redirectTo?: string; + } +>; + +/** + * @experimental The component is experimental and subject to change in future releases. + */ +export function experimental__Gate(gateProps: GateServerComponentProps) { + const { children, fallback, redirectTo, ...restAuthorizedParams } = gateProps; + const { experimental__has } = auth(); + + const isAuthorizedUser = experimental__has(restAuthorizedParams); + + const handleFallback = () => { + if (!redirectTo && !fallback) { + throw new Error('Provide `` with a `fallback` or `redirectTo`'); + } + + if (redirectTo) { + return redirect(redirectTo); + } + + return <>{fallback}; + }; + + if (!isAuthorizedUser) { + return handleFallback(); + } + + return <>{children}; +} diff --git a/packages/nextjs/src/client-boundary/controlComponents.ts b/packages/nextjs/src/client-boundary/controlComponents.ts index 5b7c92e29a..2ce6bb6333 100644 --- a/packages/nextjs/src/client-boundary/controlComponents.ts +++ b/packages/nextjs/src/client-boundary/controlComponents.ts @@ -5,6 +5,7 @@ export { ClerkLoading, SignedOut, SignedIn, + Experimental__Gate, RedirectToSignIn, RedirectToSignUp, RedirectToUserProfile, diff --git a/packages/nextjs/src/components.client.ts b/packages/nextjs/src/components.client.ts index 2fcf82aa99..3bdb446014 100644 --- a/packages/nextjs/src/components.client.ts +++ b/packages/nextjs/src/components.client.ts @@ -1,2 +1,2 @@ export { ClerkProvider } from './client-boundary/ClerkProvider'; -export { SignedIn, SignedOut } from './client-boundary/controlComponents'; +export { SignedIn, SignedOut, Experimental__Gate } from './client-boundary/controlComponents'; diff --git a/packages/nextjs/src/components.server.ts b/packages/nextjs/src/components.server.ts index a18963af32..e002e1b086 100644 --- a/packages/nextjs/src/components.server.ts +++ b/packages/nextjs/src/components.server.ts @@ -1,10 +1,11 @@ import { ClerkProvider } from './app-router/server/ClerkProvider'; -import { SignedIn, SignedOut } from './app-router/server/controlComponents'; +import { experimental__Gate, SignedIn, SignedOut } from './app-router/server/controlComponents'; -export { ClerkProvider, SignedOut, SignedIn }; +export { ClerkProvider, SignedOut, SignedIn, experimental__Gate as Experimental__Gate }; export type ServerComponentsServerModuleTypes = { ClerkProvider: typeof ClerkProvider; SignedIn: typeof SignedIn; SignedOut: typeof SignedOut; + Experimental__Gate: typeof experimental__Gate; }; diff --git a/packages/nextjs/src/index.ts b/packages/nextjs/src/index.ts index ed565c7873..6b4c171424 100644 --- a/packages/nextjs/src/index.ts +++ b/packages/nextjs/src/index.ts @@ -93,6 +93,12 @@ export const ClerkProvider = ComponentsModule.ClerkProvider as ServerComponentsS export const SignedIn = ComponentsModule.SignedIn as ServerComponentsServerModuleTypes['SignedIn']; export const SignedOut = ComponentsModule.SignedOut as ServerComponentsServerModuleTypes['SignedOut']; +/** + * @experimental + */ +export const Experimental__Gate = + ComponentsModule.Experimental__Gate as ServerComponentsServerModuleTypes['Experimental__Gate']; + export const auth = ServerHelperModule.auth as ServerHelpersServerModuleTypes['auth']; export const currentUser = ServerHelperModule.currentUser as ServerHelpersServerModuleTypes['currentUser']; // export const getAuth = ServerHelperModule.getAuth as ServerHelpersServerModuleTypes['getAuth']; diff --git a/packages/react/src/components/controlComponents.tsx b/packages/react/src/components/controlComponents.tsx index 2079110210..983a647210 100644 --- a/packages/react/src/components/controlComponents.tsx +++ b/packages/react/src/components/controlComponents.tsx @@ -1,10 +1,11 @@ -import type { HandleOAuthCallbackParams } from '@clerk/types'; +import type { experimental__CheckAuthorizationWithoutPermission, HandleOAuthCallbackParams } from '@clerk/types'; import React from 'react'; import { useAuthContext } from '../contexts/AuthContext'; import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; import { useSessionContext } from '../contexts/SessionContext'; import { LoadedGuarantee } from '../contexts/StructureContext'; +import { useAuth } from '../hooks'; import type { RedirectToSignInProps, RedirectToSignUpProps, WithClerkProp } from '../types'; import { withClerk } from './withClerk'; @@ -40,6 +41,25 @@ export const ClerkLoading = ({ children }: React.PropsWithChildren): JS return <>{children}; }; +type GateProps = React.PropsWithChildren< + Parameters[0] & { + fallback?: React.ReactNode; + } +>; + +/** + * @experimental The component is experimental and subject to change in future releases. + */ +export const experimental__Gate = ({ children, fallback, ...restAuthorizedParams }: GateProps) => { + const { experimental__has } = useAuth(); + + if (experimental__has(restAuthorizedParams)) { + return <>{children}; + } + + return <>{fallback ?? null}; +}; + export const RedirectToSignIn = withClerk(({ clerk, ...props }: WithClerkProp) => { const { client, session } = clerk; // TODO: Remove temp use of __unstable__environment diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts index 1d00b724a3..55c0949dbb 100644 --- a/packages/react/src/components/index.ts +++ b/packages/react/src/components/index.ts @@ -14,6 +14,7 @@ export { ClerkLoading, SignedOut, SignedIn, + experimental__Gate as Experimental__Gate, RedirectToSignIn, RedirectToSignUp, RedirectToUserProfile, diff --git a/packages/react/src/hooks/useAuth.ts b/packages/react/src/hooks/useAuth.ts index 293639e92d..7cfb14f788 100644 --- a/packages/react/src/hooks/useAuth.ts +++ b/packages/react/src/hooks/useAuth.ts @@ -1,4 +1,10 @@ -import type { ActJWTClaim, GetToken, MembershipRole, SignOut } from '@clerk/types'; +import type { + ActJWTClaim, + experimental__CheckAuthorizationWithoutPermission, + GetToken, + MembershipRole, + SignOut, +} from '@clerk/types'; import { useCallback } from 'react'; import { useAuthContext } from '../contexts/AuthContext'; @@ -7,6 +13,10 @@ import { invalidStateError } from '../errors'; import type IsomorphicClerk from '../isomorphicClerk'; import { createGetToken, createSignOut } from './utils'; +type experimental__CheckAuthorizationSignedOut = ( + params?: Parameters[0], +) => false; + type UseAuthReturn = | { isLoaded: false; @@ -17,6 +27,10 @@ type UseAuthReturn = orgId: undefined; orgRole: undefined; orgSlug: undefined; + /** + * @experimental The method is experimental and subject to change in future releases. + */ + experimental__has: experimental__CheckAuthorizationSignedOut; signOut: SignOut; getToken: GetToken; } @@ -29,6 +43,10 @@ type UseAuthReturn = orgId: null; orgRole: null; orgSlug: null; + /** + * @experimental The method is experimental and subject to change in future releases. + */ + experimental__has: experimental__CheckAuthorizationSignedOut; signOut: SignOut; getToken: GetToken; } @@ -41,6 +59,10 @@ type UseAuthReturn = orgId: null; orgRole: null; orgSlug: null; + /** + * @experimental The method is experimental and subject to change in future releases. + */ + experimental__has: experimental__CheckAuthorizationSignedOut; signOut: SignOut; getToken: GetToken; } @@ -53,6 +75,10 @@ type UseAuthReturn = orgId: string; orgRole: MembershipRole; orgSlug: string | null; + /** + * @experimental The method is experimental and subject to change in future releases. + */ + experimental__has: experimental__CheckAuthorizationWithoutPermission; signOut: SignOut; getToken: GetToken; }; @@ -105,6 +131,24 @@ export const useAuth: UseAuth = () => { const getToken: GetToken = useCallback(createGetToken(isomorphicClerk), [isomorphicClerk]); const signOut: SignOut = useCallback(createSignOut(isomorphicClerk), [isomorphicClerk]); + const has = useCallback( + (params?: Parameters[0]) => { + if (!orgId || !userId || !orgRole) { + return false; + } + + if (!params) { + return false; + } + + if (params.role) { + return orgRole === params.role; + } + return false; + }, + [orgId, orgRole, userId], + ); + if (sessionId === undefined && userId === undefined) { return { isLoaded: false, @@ -115,6 +159,7 @@ export const useAuth: UseAuth = () => { orgId: undefined, orgRole: undefined, orgSlug: undefined, + experimental__has: () => false, signOut, getToken, }; @@ -130,6 +175,7 @@ export const useAuth: UseAuth = () => { orgId: null, orgRole: null, orgSlug: null, + experimental__has: () => false, signOut, getToken, }; @@ -145,6 +191,7 @@ export const useAuth: UseAuth = () => { orgId, orgRole, orgSlug: orgSlug || null, + experimental__has: has, signOut, getToken, }; @@ -160,6 +207,7 @@ export const useAuth: UseAuth = () => { orgId: null, orgRole: null, orgSlug: null, + experimental__has: () => false, signOut, getToken, }; diff --git a/packages/react/src/utils/deriveState.ts b/packages/react/src/utils/deriveState.ts index c22204d279..74770e84ac 100644 --- a/packages/react/src/utils/deriveState.ts +++ b/packages/react/src/utils/deriveState.ts @@ -10,10 +10,10 @@ export const deriveState = (clerkLoaded: boolean, state: Resources, initialState const deriveFromSsrInitialState = (initialState: InitialState) => { const userId = initialState.userId; - const user = initialState.user as any as UserResource; + const user = initialState.user as UserResource; const sessionId = initialState.sessionId; - const session = initialState.session as any as ActiveSessionResource; - const organization = initialState.organization as any as OrganizationResource; + const session = initialState.session as ActiveSessionResource; + const organization = initialState.organization as OrganizationResource; const orgId = initialState.orgId; const orgRole = initialState.orgRole as MembershipRole; const orgSlug = initialState.orgSlug; @@ -46,6 +46,7 @@ const deriveFromClientSideState = (state: Resources) => { const membership = organization ? user?.organizationMemberships?.find(om => om.organization.id === orgId) : organization; + const orgPermissions = membership ? membership.permissions : membership; const orgRole = membership ? membership.role : membership; const lastOrganizationInvitation = state.lastOrganizationInvitation; @@ -60,6 +61,7 @@ const deriveFromClientSideState = (state: Resources) => { orgId, orgRole, orgSlug, + orgPermissions, actor, lastOrganizationInvitation, lastOrganizationMember, diff --git a/packages/types/src/jwtv2.ts b/packages/types/src/jwtv2.ts index 21963b8501..14151e8d55 100644 --- a/packages/types/src/jwtv2.ts +++ b/packages/types/src/jwtv2.ts @@ -112,5 +112,6 @@ export interface JwtPayload extends CustomJwtSessionClaims { */ export interface ActClaim { sub: string; + [x: string]: unknown; } diff --git a/packages/types/src/session.ts b/packages/types/src/session.ts index 3eaecba62e..e6455d2489 100644 --- a/packages/types/src/session.ts +++ b/packages/types/src/session.ts @@ -4,11 +4,27 @@ import type { ClerkResource } from './resource'; import type { TokenResource } from './token'; import type { UserResource } from './user'; -export type IsAuthorized = (isAuthorizedParams: IsAuthorizedParams) => Promise; +export type experimental__CheckAuthorizationWithoutPermission = ( + isAuthorizedParams: CheckAuthorizationParamsWithoutPermission, +) => boolean; -type IsAuthorizedParams = +type CheckAuthorizationParamsWithoutPermission = | { - any: ( + some: { + role: string; + }[]; + role?: never; + } + | { + some?: never; + role: string; + }; + +export type CheckAuthorization = (isAuthorizedParams: CheckAuthorizationParams) => boolean; + +type CheckAuthorizationParams = + | { + some: ( | { role: string; permission?: never; @@ -24,20 +40,18 @@ type IsAuthorizedParams = permission?: never; } | { - any?: never; + some?: never; role: string; permission?: never; } | { - any?: never; + some?: never; role?: never; // Adding (string & {}) allows for getting eslint autocomplete but also accepts any string // eslint-disable-next-line permission: OrganizationPermission | (string & {}); }; -type IsAuthorizedReturnValues = boolean; - export interface SessionResource extends ClerkResource { id: string; status: SessionStatus; @@ -56,7 +70,7 @@ export interface SessionResource extends ClerkResource { /** * @experimental The method is experimental and subject to change in future releases. */ - isAuthorized: IsAuthorized; + experimental__checkAuthorization: CheckAuthorization; clearCache: () => void; createdAt: Date; updatedAt: Date;