Skip to content

Commit

Permalink
feat(nextjs): Accept redirectUrl as option for auth().protect() #…
Browse files Browse the repository at this point in the history
…2329 (#2333)

* feat(nextjs): Accept `redirectUrl` as option for `auth().protect()`

* feat(nextjs): Allow for redirectUrl to be the first parameter

* chore(nextjs): Update changeset
  • Loading branch information
panteliselef authored Dec 13, 2023
1 parent b4868ab commit 96b9bb5
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 14 deletions.
16 changes: 16 additions & 0 deletions .changeset/thirty-chicken-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@clerk/nextjs': patch
---

Accept `redirectUrl` as an option for `auth().protect()`.

For example:

```ts
// Authorization
auth().protect({ role:'org:admin' }, { redirectUrl: "/any-page" })
auth().protect({ permission:'org:settings:manage' }, { redirectUrl: "/any-page" })

// Authentication
auth().protect({ redirectUrl: "/any-page" })
```
51 changes: 37 additions & 14 deletions packages/nextjs/src/app-router/server/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type {
CheckAuthorizationParamsWithCustomPermissions,
CheckAuthorizationWithCustomPermissions,
} from '@clerk/types';
import { notFound } from 'next/navigation';
import { notFound, redirect } from 'next/navigation';

import { authAuthHeaderMissing } from '../../server/errors';
import { buildClerkProps, createGetAuth } from '../../server/getAuth';
Expand All @@ -17,14 +17,23 @@ type AuthSignedIn = AuthObjectWithDeprecatedResources<
* This function is experimental as it throws a Nextjs notFound error if user is not authenticated or authorized.
* In the future we would investigate a way to throw a more appropriate error that clearly describes the not authorized of authenticated status.
*/
protect: (
params?:
| CheckAuthorizationParamsWithCustomPermissions
| ((has: CheckAuthorizationWithCustomPermissions) => boolean),
) => AuthObjectWithDeprecatedResources<SignedInAuthObject>;
protect: {
(
params?:
| CheckAuthorizationParamsWithCustomPermissions
| ((has: CheckAuthorizationWithCustomPermissions) => boolean),
options?: { redirectUrl: string },
): AuthObjectWithDeprecatedResources<SignedInAuthObject>;

(params?: { redirectUrl: string }): AuthObjectWithDeprecatedResources<SignedInAuthObject>;
};
}
>;

type ProtectGeneric = {
protect: (params?: unknown, options?: unknown) => AuthObjectWithDeprecatedResources<SignedInAuthObject>;
};

type AuthSignedOut = AuthObjectWithDeprecatedResources<
SignedOutAuthObject & {
/**
Expand All @@ -42,39 +51,53 @@ export const auth = () => {
noAuthStatusMessage: authAuthHeaderMissing(),
})(buildRequestLike());

(authObject as AuthSignedIn).protect = params => {
(authObject as unknown as ProtectGeneric).protect = (params: any, options: any) => {
const paramsOrFunction = params?.redirectUrl
? undefined
: (params as
| CheckAuthorizationParamsWithCustomPermissions
| ((has: CheckAuthorizationWithCustomPermissions) => boolean));
const redirectUrl = (params?.redirectUrl || options?.redirectUrl) as string | undefined;

const handleUnauthorized = (): never => {
if (redirectUrl) {
redirect(redirectUrl);
}
notFound();
};

/**
* User is not authenticated
*/
if (!authObject.userId) {
notFound();
return handleUnauthorized();
}

/**
* User is authenticated
*/
if (!params) {
if (!paramsOrFunction) {
return { ...authObject };
}

/**
* if a function is passed and returns false then throw not found
*/
if (typeof params === 'function') {
if (params(authObject.has)) {
if (typeof paramsOrFunction === 'function') {
if (paramsOrFunction(authObject.has)) {
return { ...authObject };
}
notFound();
return handleUnauthorized();
}

/**
* Checking if user is authorized when permission or role is passed
*/
if (authObject.has(params)) {
if (authObject.has(paramsOrFunction)) {
return { ...authObject };
}

notFound();
return handleUnauthorized();
};

return authObject as AuthSignedIn | AuthSignedOut;
Expand Down

0 comments on commit 96b9bb5

Please sign in to comment.