-
Notifications
You must be signed in to change notification settings - Fork 434
feat(clerk-js,shared): SignUp email link verification #7745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c275e5e
03e5558
be80a61
585cd53
c004686
923f052
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| '@clerk/clerk-js': minor | ||
| '@clerk/shared': minor | ||
| '@clerk/react': minor | ||
| --- | ||
|
|
||
| Add support for email link based verification to SignUpFuture | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import { inBrowser } from '@clerk/shared/browser'; | ||
| import { type ClerkError, ClerkRuntimeError, isCaptchaError, isClerkAPIResponseError } from '@clerk/shared/error'; | ||
| import { createValidatePassword } from '@clerk/shared/internal/clerk-js/passwords/password'; | ||
| import { windowNavigate } from '@clerk/shared/internal/clerk-js/windowNavigate'; | ||
|
|
@@ -24,6 +25,7 @@ import type { | |
| SignUpField, | ||
| SignUpFutureCreateParams, | ||
| SignUpFutureEmailCodeVerifyParams, | ||
| SignUpFutureEmailLinkSendParams, | ||
| SignUpFutureFinalizeParams, | ||
| SignUpFuturePasswordParams, | ||
| SignUpFuturePhoneCodeSendParams, | ||
|
|
@@ -591,21 +593,30 @@ export class SignUp extends BaseResource implements SignUpResource { | |
|
|
||
| type SignUpFutureVerificationsMethods = Pick< | ||
| SignUpFutureVerifications, | ||
| 'sendEmailCode' | 'verifyEmailCode' | 'sendPhoneCode' | 'verifyPhoneCode' | ||
| | 'sendEmailCode' | ||
| | 'verifyEmailCode' | ||
| | 'sendEmailLink' | ||
| | 'waitForEmailLinkVerification' | ||
| | 'sendPhoneCode' | ||
| | 'verifyPhoneCode' | ||
| >; | ||
|
|
||
| class SignUpFutureVerifications implements SignUpFutureVerificationsType { | ||
| #resource: SignUp; | ||
|
|
||
| sendEmailCode: SignUpFutureVerificationsType['sendEmailCode']; | ||
| verifyEmailCode: SignUpFutureVerificationsType['verifyEmailCode']; | ||
| sendEmailLink: SignUpFutureVerificationsType['sendEmailLink']; | ||
| waitForEmailLinkVerification: SignUpFutureVerificationsType['waitForEmailLinkVerification']; | ||
| sendPhoneCode: SignUpFutureVerificationsType['sendPhoneCode']; | ||
| verifyPhoneCode: SignUpFutureVerificationsType['verifyPhoneCode']; | ||
|
|
||
| constructor(resource: SignUp, methods: SignUpFutureVerificationsMethods) { | ||
| this.#resource = resource; | ||
| this.sendEmailCode = methods.sendEmailCode; | ||
| this.verifyEmailCode = methods.verifyEmailCode; | ||
| this.sendEmailLink = methods.sendEmailLink; | ||
| this.waitForEmailLinkVerification = methods.waitForEmailLinkVerification; | ||
| this.sendPhoneCode = methods.sendPhoneCode; | ||
| this.verifyPhoneCode = methods.verifyPhoneCode; | ||
| } | ||
|
|
@@ -625,6 +636,30 @@ class SignUpFutureVerifications implements SignUpFutureVerificationsType { | |
| get externalAccount() { | ||
| return this.#resource.verifications.externalAccount; | ||
| } | ||
|
|
||
| get emailLinkVerification() { | ||
| if (!inBrowser()) { | ||
| return null; | ||
| } | ||
|
|
||
| const status = getClerkQueryParam('__clerk_status') as 'verified' | 'expired' | 'failed' | 'client_mismatch'; | ||
| const createdSessionId = getClerkQueryParam('__clerk_created_session'); | ||
|
|
||
| if (!status || !createdSessionId) { | ||
| return null; | ||
| } | ||
|
|
||
| const verifiedFromTheSameClient = | ||
| status === 'verified' && | ||
| typeof SignUp.clerk.client !== 'undefined' && | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is |
||
| SignUp.clerk.client.sessions.some(s => s.id === createdSessionId); | ||
|
|
||
| return { | ||
| status, | ||
| createdSessionId, | ||
| verifiedFromTheSameClient, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| class SignUpFuture implements SignUpFutureResource { | ||
|
|
@@ -638,6 +673,8 @@ class SignUpFuture implements SignUpFutureResource { | |
| this.verifications = new SignUpFutureVerifications(this.#resource, { | ||
| sendEmailCode: this.sendEmailCode.bind(this), | ||
| verifyEmailCode: this.verifyEmailCode.bind(this), | ||
| sendEmailLink: this.sendEmailLink.bind(this), | ||
| waitForEmailLinkVerification: this.waitForEmailLinkVerification.bind(this), | ||
| sendPhoneCode: this.sendPhoneCode.bind(this), | ||
| verifyPhoneCode: this.verifyPhoneCode.bind(this), | ||
| }); | ||
|
|
@@ -833,6 +870,46 @@ class SignUpFuture implements SignUpFutureResource { | |
| }); | ||
| } | ||
|
|
||
| async sendEmailLink(params: SignUpFutureEmailLinkSendParams): Promise<{ error: ClerkError | null }> { | ||
| const { verificationUrl } = params; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need a client-only guard?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a what
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean, none of the other methods do that so probably no?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. This one uses |
||
| return runAsyncResourceTask(this.#resource, async () => { | ||
| let absoluteVerificationUrl = verificationUrl; | ||
| try { | ||
| new URL(verificationUrl); | ||
| } catch { | ||
| absoluteVerificationUrl = window.location.origin + verificationUrl; | ||
| } | ||
|
|
||
| await this.#resource.__internal_basePost({ | ||
| body: { strategy: 'email_link', redirectUrl: absoluteVerificationUrl }, | ||
| action: 'prepare_verification', | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| async waitForEmailLinkVerification(): Promise<{ error: ClerkError | null }> { | ||
| return runAsyncResourceTask(this.#resource, async () => { | ||
| const { run, stop } = Poller(); | ||
| await new Promise((resolve, reject) => { | ||
| void run(() => { | ||
| return this.#resource | ||
| .reload() | ||
| .then(res => { | ||
| const status = res.verifications.emailAddress.status; | ||
| if (status === 'verified' || status === 'expired') { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these all of the statuses that should short-circuit the poller? Saw these also
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, the existing I think (maybe?) those statuses are possible in the |
||
| stop(); | ||
| resolve(res); | ||
| } | ||
| }) | ||
| .catch(err => { | ||
| stop(); | ||
| reject(err); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| async sendPhoneCode(params: SignUpFuturePhoneCodeSendParams): Promise<{ error: ClerkError | null }> { | ||
| const { phoneNumber, channel = 'sms' } = params; | ||
| return runAsyncResourceTask(this.#resource, async () => { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hyphenate the compound adjective.
The phrase "email link based" should be hyphenated as "email-link-based" when used as a compound adjective modifying "verification".
✏️ Proposed fix
📝 Committable suggestion
🧰 Tools
🪛 LanguageTool
[grammar] ~7-~7: Use a hyphen to join words.
Context: ...': minor --- Add support for email link based verification to SignUpFuture
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents