Skip to content

Commit fefe438

Browse files
committed
feat: add redirectToSignUp() to ClerkMiddlewareAuthObject
1 parent f59a90b commit fefe438

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

Diff for: packages/nextjs/src/app-router/server/auth.ts

+32-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ type Auth = AuthObject & {
2525
* `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).
2626
*/
2727
redirectToSignIn: RedirectFun<ReturnType<typeof redirect>>;
28+
29+
/**
30+
* The `auth()` helper returns the `redirectToSignUp()` method, which you can use to redirect the user to the sign-up page.
31+
*
32+
* @param [returnBackUrl] {string | URL} - The URL to redirect the user back to after they sign up.
33+
*
34+
* @note
35+
* `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).
36+
*/
37+
redirectToSignUp: RedirectFun<ReturnType<typeof redirect>>;
2838
};
2939

3040
export interface AuthFn {
@@ -104,7 +114,28 @@ export const auth: AuthFn = async () => {
104114
});
105115
};
106116

107-
return Object.assign(authObject, { redirectToSignIn });
117+
const redirectToSignUp: RedirectFun<never> = (opts = {}) => {
118+
const clerkRequest = createClerkRequest(request);
119+
const devBrowserToken =
120+
clerkRequest.clerkUrl.searchParams.get(constants.QueryParameters.DevBrowser) ||
121+
clerkRequest.cookies.get(constants.Cookies.DevBrowser);
122+
123+
const encryptedRequestData = getHeader(request, constants.Headers.ClerkRequestData);
124+
const decryptedRequestData = decryptClerkRequestData(encryptedRequestData);
125+
126+
return createRedirect({
127+
redirectAdapter: redirect,
128+
devBrowserToken: devBrowserToken,
129+
baseUrl: clerkRequest.clerkUrl.toString(),
130+
publishableKey: decryptedRequestData.publishableKey || PUBLISHABLE_KEY,
131+
signInUrl: decryptedRequestData.signInUrl || SIGN_IN_URL,
132+
signUpUrl: decryptedRequestData.signUpUrl || SIGN_UP_URL,
133+
}).redirectToSignUp({
134+
returnBackUrl: opts.returnBackUrl === null ? '' : opts.returnBackUrl || clerkUrl?.toString(),
135+
});
136+
};
137+
138+
return Object.assign(authObject, { redirectToSignIn, redirectToSignUp });
108139
};
109140

110141
auth.protect = async (...args: any[]) => {

Diff for: packages/nextjs/src/server/clerkMiddleware.ts

+27-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ import {
1818
isNextjsNotFoundError,
1919
isNextjsRedirectError,
2020
isRedirectToSignInError,
21+
isRedirectToSignUpError,
2122
nextjsRedirectError,
2223
redirectToSignInError,
24+
redirectToSignUpError,
2325
} from './nextErrors';
2426
import type { AuthProtect } from './protect';
2527
import { createProtect } from './protect';
@@ -34,6 +36,7 @@ import {
3436

3537
export type ClerkMiddlewareAuthObject = AuthObject & {
3638
redirectToSignIn: RedirectFun<Response>;
39+
redirectToSignUp: RedirectFun<Response>;
3740
};
3841

3942
export interface ClerkMiddlewareAuth {
@@ -172,9 +175,13 @@ export const clerkMiddleware: ClerkMiddleware = (...args: unknown[]) => {
172175
logger.debug('auth', () => ({ auth: authObject, debug: authObject.debug() }));
173176

174177
const redirectToSignIn = createMiddlewareRedirectToSignIn(clerkRequest);
178+
const redirectToSignUp = createMiddlewareRedirectToSignUp(clerkRequest);
175179
const protect = await createMiddlewareProtect(clerkRequest, authObject, redirectToSignIn);
176180

177-
const authObjWithMethods: ClerkMiddlewareAuthObject = Object.assign(authObject, { redirectToSignIn });
181+
const authObjWithMethods: ClerkMiddlewareAuthObject = Object.assign(authObject, {
182+
redirectToSignIn,
183+
redirectToSignUp,
184+
});
178185
const authHandler = () => Promise.resolve(authObjWithMethods);
179186
authHandler.protect = protect;
180187

@@ -311,6 +318,15 @@ const createMiddlewareRedirectToSignIn = (
311318
};
312319
};
313320

321+
const createMiddlewareRedirectToSignUp = (
322+
clerkRequest: ClerkRequest,
323+
): ClerkMiddlewareAuthObject['redirectToSignUp'] => {
324+
return (opts = {}) => {
325+
const url = clerkRequest.clerkUrl.toString();
326+
redirectToSignUpError(url, opts.returnBackUrl);
327+
};
328+
};
329+
314330
const createMiddlewareProtect = (
315331
clerkRequest: ClerkRequest,
316332
authObject: AuthObject,
@@ -363,6 +379,16 @@ const handleControlFlowErrors = (
363379
}).redirectToSignIn({ returnBackUrl: e.returnBackUrl });
364380
}
365381

382+
if (isRedirectToSignUpError(e)) {
383+
return createRedirect({
384+
redirectAdapter,
385+
baseUrl: clerkRequest.clerkUrl,
386+
signInUrl: requestState.signInUrl,
387+
signUpUrl: requestState.signUpUrl,
388+
publishableKey: requestState.publishableKey,
389+
}).redirectToSignUp({ returnBackUrl: e.returnBackUrl });
390+
}
391+
366392
if (isNextjsRedirectError(e)) {
367393
return redirectAdapter(e.redirectUrl);
368394
}

Diff for: packages/nextjs/src/server/nextErrors.ts

+18
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
const CONTROL_FLOW_ERROR = {
55
REDIRECT_TO_URL: 'CLERK_PROTECT_REDIRECT_TO_URL',
66
REDIRECT_TO_SIGN_IN: 'CLERK_PROTECT_REDIRECT_TO_SIGN_IN',
7+
REDIRECT_TO_SIGN_UP: 'CLERK_PROTECT_REDIRECT_TO_SIGN_UP',
78
};
89

910
/**
@@ -99,6 +100,13 @@ function redirectToSignInError(url: string, returnBackUrl?: string | URL | null)
99100
});
100101
}
101102

103+
function redirectToSignUpError(url: string, returnBackUrl?: string | URL | null): never {
104+
nextjsRedirectError(url, {
105+
clerk_digest: CONTROL_FLOW_ERROR.REDIRECT_TO_SIGN_UP,
106+
returnBackUrl: returnBackUrl === null ? '' : returnBackUrl || url,
107+
});
108+
}
109+
102110
/**
103111
* Checks an error to determine if it's an error generated by the
104112
* `redirect(url)` helper.
@@ -135,11 +143,21 @@ function isRedirectToSignInError(error: unknown): error is RedirectError<{ retur
135143
return false;
136144
}
137145

146+
function isRedirectToSignUpError(error: unknown): error is RedirectError<{ returnBackUrl: string | URL }> {
147+
if (isNextjsRedirectError(error) && 'clerk_digest' in error) {
148+
return error.clerk_digest === CONTROL_FLOW_ERROR.REDIRECT_TO_SIGN_UP;
149+
}
150+
151+
return false;
152+
}
153+
138154
export {
139155
isNextjsNotFoundError,
140156
isLegacyNextjsNotFoundError,
141157
redirectToSignInError,
158+
redirectToSignUpError,
142159
nextjsRedirectError,
143160
isNextjsRedirectError,
144161
isRedirectToSignInError,
162+
isRedirectToSignUpError,
145163
};

0 commit comments

Comments
 (0)