Skip to content

Commit dd58c25

Browse files
authored
chore(nextjs,backend): Add & Improve JSDoc comments (clerk#4994)
1 parent 783d98c commit dd58c25

15 files changed

+354
-52
lines changed

.changeset/sour-pears-drop.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@clerk/backend': patch
3+
'@clerk/nextjs': patch
4+
---
5+
6+
Improve JSDoc comments to provide you with better IntelliSense information in your IDE

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
"turbo": "^2.0.14",
129129
"turbo-ignore": "^2.0.6",
130130
"typedoc": "0.27.6",
131+
"typedoc-plugin-missing-exports": "3.1.0",
131132
"typescript": "catalog:repo",
132133
"typescript-eslint": "8.21.0",
133134
"uuid": "8.3.2",

packages/backend/src/jwt/verifyJwt.ts

+16
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,25 @@ export function decodeJwt(token: string): JwtReturnType<Jwt, TokenVerificationEr
9494
}
9595

9696
export type VerifyJwtOptions = {
97+
/**
98+
* A string or list of [audiences](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3). If passed, it is checked against the `aud` claim in the token.
99+
*/
97100
audience?: string | string[];
101+
/**
102+
* An allowlist of origins to verify against, to protect your application from the subdomain cookie leaking attack.
103+
* @example
104+
* ```ts
105+
* authorizedParties: ['http://localhost:3000', 'https://example.com']
106+
* ```
107+
*/
98108
authorizedParties?: string[];
109+
/**
110+
* Specifies the allowed time difference (in milliseconds) between the Clerk server (which generates the token) and the clock of the user's application server when validating a token. Defaults to 5000 ms (5 seconds).
111+
*/
99112
clockSkewInMs?: number;
113+
/**
114+
* @internal
115+
*/
100116
key: JsonWebKey | string;
101117
};
102118

packages/backend/src/tokens/keys.ts

+15
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,29 @@ export function loadClerkJWKFromLocal(localKey?: string): JsonWebKey {
8585
}
8686

8787
export type LoadClerkJWKFromRemoteOptions = {
88+
/**
89+
* @internal
90+
*/
8891
kid: string;
8992
/**
9093
* @deprecated This cache TTL is deprecated and will be removed in the next major version. Specifying a cache TTL is now a no-op.
9194
*/
9295
jwksCacheTtlInMs?: number;
96+
/**
97+
* A flag to skip ignore cache and always fetch JWKS before each jwt verification.
98+
*/
9399
skipJwksCache?: boolean;
100+
/**
101+
* The Clerk Secret Key from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard.
102+
*/
94103
secretKey?: string;
104+
/**
105+
* The [Clerk Backend API](https://clerk.com/docs/reference/backend-api) endpoint. Defaults to `'https://api.clerk.com'`.
106+
*/
95107
apiUrl?: string;
108+
/**
109+
* The version passed to the Clerk API. Defaults to `'v1'`.
110+
*/
96111
apiVersion?: string;
97112
};
98113

packages/backend/src/tokens/types.ts

+79-33
Original file line numberDiff line numberDiff line change
@@ -2,68 +2,114 @@ import type { ApiClient } from '../api';
22
import type { VerifyTokenOptions } from './verify';
33

44
export type AuthenticateRequestOptions = {
5+
/**
6+
* The Clerk Publishable Key from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard.
7+
*/
58
publishableKey?: string;
9+
/**
10+
* The domain of a [satellite application](https://clerk.com/docs/advanced-usage/satellite-domains) in a multi-domain setup.
11+
*/
612
domain?: string;
13+
/**
14+
* Whether the instance is a satellite domain in a multi-domain setup. Defaults to `false`.
15+
*/
716
isSatellite?: boolean;
17+
/**
18+
* The proxy URL from a multi-domain setup.
19+
*/
820
proxyUrl?: string;
21+
/**
22+
* The sign-in URL from a multi-domain setup.
23+
*/
924
signInUrl?: string;
25+
/**
26+
* The sign-up URL from a multi-domain setup.
27+
*/
1028
signUpUrl?: string;
29+
/**
30+
* Full URL or path to navigate to after successful sign in. Defaults to `/`.
31+
*/
1132
afterSignInUrl?: string;
33+
/**
34+
* Full URL or path to navigate to after successful sign up. Defaults to `/`.
35+
*/
1236
afterSignUpUrl?: string;
37+
/**
38+
* Used to activate a specific [organization](https://clerk.com/docs/organizations/overview) or [personal account](https://clerk.com/docs/organizations/organization-workspaces#organization-workspaces-in-the-clerk-dashboard:~:text=Personal%20account) based on URL path parameters. If there's a mismatch between the active organization in the session (e.g., as reported by `auth()`) and the organization indicated by the URL, an attempt to activate the organization specified in the URL will be made.
39+
*
40+
* If the activation can't be performed, either because an organization doesn't exist or the user lacks access, the active organization in the session won't be changed. Ultimately, it's the responsibility of the page to verify that the resources are appropriate to render given the URL and handle mismatches appropriately (e.g., by returning a 404).
41+
*/
1342
organizationSyncOptions?: OrganizationSyncOptions;
43+
/**
44+
* @internal
45+
*/
1446
apiClient?: ApiClient;
1547
} & VerifyTokenOptions;
1648

1749
/**
18-
* Defines the options for syncing an organization or personal account state from the URL to the clerk session.
19-
* Useful if the application requires the inclusion of a URL that indicates that a given clerk organization
20-
* (or personal account) must be active on the clerk session.
21-
*
22-
* If a mismatch between the active organization on the session and the organization as indicated by the URL is
23-
* detected, an attempt to activate the given organization will be made.
24-
*
25-
* WARNING: If the activation cannot be performed, either because an organization does not exist or the user lacks
26-
* access, then the active organization on the session will not be changed (and a warning will be logged). It is
27-
* ultimately the responsibility of the page to verify that the resources are appropriate to render given the URL,
28-
* and handle mismatches appropriately (e.g. by returning a 404).
50+
* @expand
2951
*/
3052
export type OrganizationSyncOptions = {
3153
/**
32-
* URL patterns that are organization-specific and contain an organization ID or slug as a path token.
33-
* If a request matches this path, the organization identifier will be extracted and activated before rendering.
54+
* Specifies URL patterns that are organization-specific, containing an organization ID or slug as a path parameter. If a request matches this path, the organization identifier will be used to set that org as active.
3455
*
35-
* WARNING: If the organization cannot be activated either because it does not exist or the user lacks access,
36-
* organization-related fields will be set to null. The server component must detect this and respond
37-
* with an appropriate error (e.g., notFound()).
56+
* If the route also matches the `personalAccountPatterns` prop, this prop takes precedence.
3857
*
39-
* If the route also matches the personalAccountPatterns, this takes precedence.
58+
* Patterns must have a path parameter named either `:id` (to match a Clerk organization ID) or `:slug` (to match a Clerk organization slug).
4059
*
41-
* Must have a path token named either ":id" (matches a clerk organization ID) or ":slug" (matches a clerk
42-
* organization slug).
60+
* @warning
61+
* If the organization can't be activated—either because it doesn't exist or the user lacks access—the previously active organization will remain unchanged. Components must detect this case and provide an appropriate error and/or resolution pathway, such as calling `notFound()` or displaying an [`<OrganizationSwitcher />`](https://clerk.com/docs/components/organization/organization-switcher).
4362
*
44-
* Common examples:
45-
* - ["/orgs/:slug", "/orgs/:slug/(.*)"]
46-
* - ["/orgs/:id", "/orgs/:id/(.*)"]
47-
* - ["/app/:any/orgs/:slug", "/app/:any/orgs/:slug/(.*)"]
63+
* @example
64+
* ["/orgs/:slug", "/orgs/:slug/(.*)"]
65+
* @example
66+
* ["/orgs/:id", "/orgs/:id/(.*)"]
67+
* @example
68+
* ["/app/:any/orgs/:slug", "/app/:any/orgs/:slug/(.*)"]
4869
*/
4970
organizationPatterns?: Pattern[];
5071

5172
/**
52-
* URL patterns for resources in the context of a clerk personal account (user-specific, outside any organization).
53-
* If the route also matches the organizationPattern, the organizationPatterns takes precedence.
73+
* URL patterns for resources that exist within the context of a [Clerk Personal Account](https://clerk.com/docs/organizations/organization-workspaces#organization-workspaces-in-the-clerk-dashboard:~:text=Personal%20account) (user-specific, outside any organization).
5474
*
55-
* Common examples:
56-
* - ["/user", "/user/(.*)"]
57-
* - ["/user/:any", "/user/:any/(.*)"]
75+
* If the route also matches the `organizationPattern` prop, the `organizationPattern` prop takes precedence.
76+
*
77+
* @example
78+
* ["/user", "/user/(.*)"]
79+
* @example
80+
* ["/user/:any", "/user/:any/(.*)"]
5881
*/
5982
personalAccountPatterns?: Pattern[];
6083
};
6184

6285
/**
63-
* A pattern representing the structure of a URL path.
64-
* In addition to a valid URL, may include:
65-
* - Named path tokens prefixed with a colon (e.g., ":id", ":slug", ":any")
66-
* - Wildcard token (e.g., ".(*)"), which will match the remainder of the path
67-
* Examples: "/orgs/:slug", "/app/:any/orgs/:id", "/personal-account/(.*)"
86+
* A `Pattern` is a `string` that represents the structure of a URL path. In addition to any valid URL, it may include:
87+
* - Named path parameters prefixed with a colon (e.g., `:id`, `:slug`, `:any`).
88+
* - Wildcard token, `(.*)`, which matches the remainder of the path.
89+
*
90+
* @example
91+
* /orgs/:slug
92+
*
93+
* ```ts
94+
* '/orgs/acmecorp' // matches (`:slug` value: acmecorp)
95+
* '/orgs' // does not match
96+
* '/orgs/acmecorp/settings' // does not match
97+
* ```
98+
*
99+
* @example
100+
* /app/:any/orgs/:id
101+
*
102+
* ```ts
103+
* '/app/petstore/orgs/org_123' // matches (`:id` value: org_123)
104+
* '/app/dogstore/v2/orgs/org_123' // does not match
105+
* ```
106+
*
107+
* @example
108+
* /personal-account/(.*)
109+
*
110+
* ```ts
111+
* '/personal-account/settings' // matches
112+
* '/personal-account' // does not match
113+
* ```
68114
*/
69115
type Pattern = string;

packages/backend/src/tokens/verify.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import type { LoadClerkJWKFromRemoteOptions } from './keys';
88
import { loadClerkJWKFromLocal, loadClerkJWKFromRemote } from './keys';
99

1010
export type VerifyTokenOptions = Omit<VerifyJwtOptions, 'key'> &
11-
Omit<LoadClerkJWKFromRemoteOptions, 'kid'> & { jwtKey?: string };
11+
Omit<LoadClerkJWKFromRemoteOptions, 'kid'> & {
12+
/**
13+
* Used to verify the session token in a networkless manner. Supply the PEM public key from the **[**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page -> Show JWT public key -> PEM Public Key** section in the Clerk Dashboard. **It's recommended to use [the environment variable](https://clerk.com/docs/deployments/clerk-environment-variables) instead.** For more information, refer to [Manual JWT verification](https://clerk.com/docs/backend-requests/handling/manual-jwt).
14+
*/
15+
jwtKey?: string;
16+
};
1217

1318
export async function verifyToken(
1419
token: string,

packages/nextjs/src/app-router/server/auth.ts

+39-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,50 @@ import { createProtect } from '../../server/protect';
1111
import { decryptClerkRequestData } from '../../server/utils';
1212
import { buildRequestLike } from './utils';
1313

14-
type Auth = AuthObject & { redirectToSignIn: RedirectFun<ReturnType<typeof redirect>> };
15-
14+
/**
15+
* `Auth` object of the currently active user and the `redirectToSignIn()` method.
16+
*/
17+
type Auth = AuthObject & {
18+
/**
19+
* The `auth()` helper returns the `redirectToSignIn()` method, which you can use to redirect the user to the sign-in page.
20+
*
21+
* @param [returnBackUrl] {string | URL} - The URL to redirect the user back to after they sign in.
22+
*
23+
* @note
24+
* `auth()` on the server-side can only access redirect URLs defined via [environment variables](https://clerk.com/docs/deployments/clerk-environment-variables#sign-in-and-sign-up-redirects) or [`clerkMiddleware` dynamic keys](https://clerk.com/docs/references/nextjs/clerk-middleware#dynamic-keys).
25+
*/
26+
redirectToSignIn: RedirectFun<ReturnType<typeof redirect>>;
27+
};
1628
export interface AuthFn {
1729
(): Promise<Auth>;
30+
/**
31+
* `auth` includes a single property, the `protect()` method, which you can use in two ways:
32+
* - to check if a user is authenticated (signed in)
33+
* - to check if a user is authorized (has the correct roles or permissions) to access something, such as a component or a route handler
34+
*
35+
* The following table describes how auth.protect() behaves based on user authentication or authorization status:
36+
*
37+
* | Authenticated | Authorized | `auth.protect()` will |
38+
* | - | - | - |
39+
* | Yes | Yes | Return the [`Auth`](https://clerk.com/docs/references/backend/types/auth-object) object. |
40+
* | Yes | No | Return a `404` error. |
41+
* | No | No | Redirect the user to the sign-in page\*. |
42+
*
43+
* @important
44+
* \*For non-document requests, such as API requests, `auth.protect()` returns a `404` error to users who aren't authenticated.
45+
*
46+
* `auth.protect()` can be used to check if a user is authenticated or authorized to access certain parts of your application or even entire routes. See detailed examples in the [dedicated guide](https://clerk.com/docs/organizations/verify-user-permissions).
47+
*/
1848
protect: AuthProtect;
1949
}
2050

51+
/**
52+
* The `auth()` helper returns the [`Auth`](https://clerk.com/docs/references/backend/types/auth-object) object of the currently active user, as well as the [`redirectToSignIn()`](https://clerk.com/docs/references/nextjs/auth#redirect-to-sign-in) method.
53+
*
54+
* - Only available for App Router.
55+
* - Only works on the server-side, such as in Server Components, Route Handlers, and Server Actions.
56+
* - Requires [`clerkMiddleware()`](https://clerk.com/docs/references/nextjs/clerk-middleware) to be configured.
57+
*/
2158
export const auth: AuthFn = async () => {
2259
// eslint-disable-next-line @typescript-eslint/no-require-imports
2360
require('server-only');

packages/nextjs/src/app-router/server/currentUser.ts

+23
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@ import type { User } from '@clerk/backend';
33
import { clerkClient } from '../../server/clerkClient';
44
import { auth } from './auth';
55

6+
/**
7+
* The `currentUser` helper returns the [Backend User](https://clerk.com/docs/references/backend/types/backend-user) object of the currently active user. It can be used in Server Components, Route Handlers, and Server Actions.
8+
*
9+
* Under the hood, this helper:
10+
* - calls `fetch()`, so it is automatically deduped per request.
11+
* - uses the [`GET /v1/users/{user_id}`](https://clerk.com/docs/reference/backend-api/tag/Users#operation/GetUser) endpoint.
12+
* - counts towards the [Backend API request rate limit](https://clerk.com/docs/backend-requests/resources/rate-limits#rate-limits).
13+
*
14+
* @example
15+
* ```tsx
16+
* // app/page.tsx
17+
*
18+
* import { currentUser } from '@clerk/nextjs/server'
19+
*
20+
* export default async function Page() {
21+
* const user = await currentUser()
22+
*
23+
* if (!user) return <div>Not signed in</div>
24+
*
25+
* return <div>Hello {user?.firstName}</div>
26+
* }
27+
* ```
28+
*/
629
export async function currentUser(): Promise<User | null> {
730
// eslint-disable-next-line @typescript-eslint/no-require-imports
831
require('server-only');

packages/nextjs/src/server/buildClerkProps.ts

+41-13
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,52 @@ import type { RequestLike } from './types';
66

77
type BuildClerkPropsInitState = { user?: User | null; session?: Session | null; organization?: Organization | null };
88

9+
type BuildClerkProps = (req: RequestLike, authState?: BuildClerkPropsInitState) => Record<string, unknown>;
10+
911
/**
10-
* To enable Clerk SSR support, include this object to the `props`
11-
* returned from `getServerSideProps`. This will automatically make the auth state available to
12-
* the Clerk components and hooks during SSR, the hydration phase and CSR.
12+
* Clerk uses `buildClerkProps` to inform the client-side helpers of the authentication state of the user. This function is used SSR in the `getServerSideProps` function of your Next.js application.
13+
*
14+
* @example
15+
* **Basic usage**
16+
*
17+
* ```tsx
18+
* // pages/myServerSidePage.tsx
19+
*
20+
* import { getAuth, buildClerkProps } from '@clerk/nextjs/server'
21+
* import { GetServerSideProps } from 'next'
22+
*
23+
* export const getServerSideProps: GetServerSideProps = async (ctx) => {
24+
* const { userId } = getAuth(ctx.req)
25+
*
26+
* if (!userId) {
27+
* // handle user is not signed in.
28+
* }
29+
*
30+
* // Load any data your application needs for the page using the userId
31+
* return { props: { ...buildClerkProps(ctx.req) } }
32+
* }
33+
* ```
34+
*
1335
* @example
14-
* import { getAuth } from '@clerk/nextjs/server';
36+
* **Usage with `clerkClient`**
37+
*
38+
* The `clerkClient` allows you to access the Clerk API. You can use this to retrieve or update data.
39+
*
40+
* ```tsx
41+
* // pages/api/example.ts
1542
*
16-
* export const getServerSideProps = ({ req }) => {
17-
* const { authServerSideProps } = getAuth(req);
18-
* const myData = getMyData();
43+
* import { getAuth, buildClerkProps, clerkClient } from '@clerk/nextjs/server'
44+
* import { GetServerSideProps } from 'next'
1945
*
20-
* return {
21-
* props: { myData, authServerSideProps },
22-
* };
23-
* };
46+
* export const getServerSideProps: GetServerSideProps = async (ctx) => {
47+
* const { userId } = getAuth(ctx.req)
48+
*
49+
* const user = userId ? await clerkClient().users.getUser(userId) : undefined
50+
*
51+
* return { props: { ...buildClerkProps(ctx.req, { user }) } }
52+
* }
53+
* ```
2454
*/
25-
type BuildClerkProps = (req: RequestLike, authState?: BuildClerkPropsInitState) => Record<string, unknown>;
26-
2755
export const buildClerkProps: BuildClerkProps = (req, initialState = {}) => {
2856
const sanitizedAuthObject = getDynamicAuthData(req, initialState);
2957

0 commit comments

Comments
 (0)