Skip to content

Commit

Permalink
fix(clerk-js): Make email-link return to application instead of AP (#…
Browse files Browse the repository at this point in the history
…2727)

* fix(clerk-js): Use signInUrl from context as email-link redirectUrl

The signInUrl used in email-link will be retrieved from the props or
context or repo-level or display config (with the same priority as
listed here).
In applications that the sign-in url is defined the
email-link verification will redirect to the application without passing
through the AP first. This results in fixing the handshake for email-
link flows.
Note: Applications using the signInUrl from the Dashboard settings, will
not support the handshake flow and would require an additional redirect
to FAPI/v1/client/handshake on email-link verification to work.

* fix(clerk-js): Make path-based routing the default in redirects

* fix(clerk-js): Fix type

---------

Co-authored-by: Nikos Douvlis <nikosdouvlis@gmail.com>
  • Loading branch information
dimkl and nikosdouvlis committed Feb 6, 2024
1 parent ee57f21 commit 5d6937c
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/tiny-beds-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-js': minor
---

Use signInUrl from props/ context / repo-level to construct a redirectUrl in email-link flow.
10 changes: 5 additions & 5 deletions packages/clerk-js/src/ui/common/__tests__/redirects.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { buildEmailLinkRedirectUrl, buildSSOCallbackURL } from '../redirects';

describe('buildEmailLinkRedirectUrl(routing, baseUrl)', () => {
it('handles empty routing strategy based routing ', function () {
expect(buildEmailLinkRedirectUrl({ path: '', authQueryString: '' } as any, '')).toBe('http://localhost/#/verify');
it('defaults to path based routing strategy on empty routing', function () {
expect(buildEmailLinkRedirectUrl({ path: '', authQueryString: '' } as any, '')).toBe('http://localhost/verify');
});

it('returns the magic link redirect url for components using path based routing ', function () {
Expand Down Expand Up @@ -129,10 +129,10 @@ describe('buildEmailLinkRedirectUrl(routing, baseUrl)', () => {
describe('buildSSOCallbackURL(ctx, baseUrl)', () => {
it('returns the SSO callback URL based on sign in|up component routing or the provided base URL', () => {
// Default callback URLS
expect(buildSSOCallbackURL({}, '')).toBe('http://localhost/#/sso-callback');
expect(buildSSOCallbackURL({}, 'http://test.host')).toBe('http://localhost/#/sso-callback');
expect(buildSSOCallbackURL({}, '')).toBe('http://localhost/sso-callback');
expect(buildSSOCallbackURL({}, 'http://test.host')).toBe('http://localhost/sso-callback');
expect(buildSSOCallbackURL({ authQueryString: 'redirect_url=%2Ffoo' }, 'http://test.host')).toBe(
'http://localhost/#/sso-callback?redirect_url=%2Ffoo',
'http://localhost/sso-callback?redirect_url=%2Ffoo',
);

// Components mounted with hash routing
Expand Down
4 changes: 2 additions & 2 deletions packages/clerk-js/src/ui/common/redirects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ type BuildRedirectUrlParams = {
};

const buildRedirectUrl = ({ routing, authQueryString, baseUrl, path, endpoint }: BuildRedirectUrlParams): string => {
if (!routing || routing === 'hash') {
if (routing === 'hash') {
return buildHashBasedUrl(authQueryString, endpoint);
}

if (routing === 'path') {
if (!routing || routing === 'path') {
return buildPathBasedUrl(path || '', authQueryString, endpoint);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React from 'react';

import { EmailLinkStatusCard } from '../../common';
import { buildEmailLinkRedirectUrl } from '../../common/redirects';
import { useCoreSignIn, useEnvironment, useSignInContext } from '../../contexts';
import { useCoreSignIn, useSignInContext } from '../../contexts';
import { Flow, localizationKeys, useLocalizations } from '../../customizables';
import type { VerificationCodeCardProps } from '../../elements';
import { VerificationLinkCard } from '../../elements';
Expand All @@ -25,7 +25,7 @@ export const SignInFactorOneEmailLinkCard = (props: SignInFactorOneEmailLinkCard
const card = useCardState();
const signIn = useCoreSignIn();
const signInContext = useSignInContext();
const { signInUrl } = useEnvironment().displayConfig;
const { signInUrl } = signInContext;
const { navigate } = useRouter();
const { navigateAfterSignIn } = useSignInContext();
const { setActive } = useClerk();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ describe('SignInStart', () => {
expect(fixtures.signIn.create).toHaveBeenCalled();
expect(fixtures.signIn.authenticateWithRedirect).toHaveBeenCalledWith({
strategy: 'saml',
redirectUrl: 'http://localhost/#/sso-callback?redirect_url=http%3A%2F%2Flocalhost%2F',
redirectUrl: 'http://localhost/sso-callback?redirect_url=http%3A%2F%2Flocalhost%2F',
redirectUrlComplete: '/',
});
});
Expand Down
11 changes: 9 additions & 2 deletions packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export type SignInContextType = SignInCtx & {
navigateAfterSignIn: () => any;
queryParams: ParsedQs;
signUpUrl: string;
signInUrl: string;
signUpContinueUrl: string;
authQueryString: string | null;
};
Expand Down Expand Up @@ -157,24 +158,30 @@ export const useSignInContext = (): SignInContextType => {

const navigateAfterSignIn = () => navigate(afterSignInUrl);

let signUpUrl = pickRedirectionProp('signUpUrl', { ctx, options, displayConfig }, false);

// Add query strings to the sign in URL
const authQs = buildAuthQueryString({
afterSignInUrl: afterSignInUrl,
afterSignUpUrl: afterSignUpUrl,
displayConfig: displayConfig,
});

let signUpUrl = pickRedirectionProp('signUpUrl', { ctx, options, displayConfig }, false);
if (authQs && ctx.routing !== 'virtual') {
signUpUrl += `#/?${authQs}`;
}

let signInUrl = pickRedirectionProp('signInUrl', { ctx, options, displayConfig }, false);
if (authQs && ctx.routing !== 'virtual') {
signInUrl += `#/?${authQs}`;
}

const signUpContinueUrl = buildURL({ base: signUpUrl, hashPath: '/continue' }, { stringify: true });

return {
...ctx,
componentName,
signUpUrl,
signInUrl,
afterSignInUrl,
afterSignUpUrl,
navigateAfterSignIn,
Expand Down

0 comments on commit 5d6937c

Please sign in to comment.