Verify email ownership
Passlock can handle the routine task of verifying email ownership by sending a verification link or code.
You can customise the verification email and even add your own logo. Please see the emails documentation.
Via a verification link
Passlock can generate a secure link and email it to the user as part of the registration process. Whilst this may seem a trivial task, it's actually a bit more complex than it first appears.
Note: Passlock will generate secure links to your domain, not passlock.dev:
- When registering a passkey, pass the
verifyEmail
option - Passlock generates a secure link to your domain, appends
?code={code}
and emails it to the recipient - The recipient clicks the link and hits your url
- Your frontend calls
verifyEmailLink
verifyEmailLink
extracts the code from the browser url and sends it to Passlock for verification
import { Passlock } from '@passlock/client'
const passlock = new Passlock({ tenancyId, clientId })
await passlock.registerPasskey({
...
verifyEmail: {
method: 'link',
// Note: this url must comply with your RP ID
redirectUrl: 'https://mydomain.com/verify'
}
})
// this will pull the ?code=123 from the current window.location
// and send it to the Passlock backend for verification
const result = await passlock.verifyEmailLink()
Why do it this way?
In short, because we need to re-authenticate the user.
Via a verification code
Verify similar to sending a link. Passlock will email a 6 digit code to the mailbox owner. You should prompt the user to enter the code and call the verifyEmailCode
function.
await passlock.registerPasskey({
...
verifyEmail: {
method: 'code'
}
})
// Prompt the user to enter the code and call
const result = await passlock.verifyEmailCode({ code })
Link vs code
When should you choose to send a link vs a code? It depends on the complexity of your registration flow. If you have transient state in your frontend which is not immune to a page refresh, the code is a better option.
Also, Apple recently announced autofill of mailbox verification code (they've done something similar for SMS codes for a while). Assuming the user is using the latest Safari and Mail apps, Safari will scan the mailbox and autofill any codes that were sent.
Re-authenticating the user
Why do we redirect the user to your site, then ask you to send us the code? Why not send a link to passlock.dev
, check the link and then redirect them to your site? We do it for two reasons: Firstly aesthetics - a user will feel more comfortable clicking a link to your domain than ours. Secondly there is an important security aspect at play:
Verifying that someone has access to the email mailbox is not enough. We also need to ensure that the person verifying the email is the same person who registered the passkey. Otherwise you would be vulnerable to this scenario:
- Mallory registers an account using the email
alice@gmail.com
- We send a verification email to
alice@gmail.com
- Alice (who receives far too many emails) accidently clicks the link
- We have now confimed that Mallory owns
alice@gmail.com
😱
During the registerPasskey
call, Passlock will generate a secure token (the one you send to your backend for verification). We also store this in local storage. When you call verifyEmailLink
we look for this token in local storage. If we can't find it we reauthenticate the user to obtain a fresh token.
We then send both the email verification code and the token to the backend. Our backend verifies that the code is valid and relates to the same account as the authentication token.
If your're worried about us storing a credential in local storage, we clear it during the verifyEmailLink
call. You can also call clearExpiredTokens
to delete any tokens from local storage. In addition, tokens are only valid for 5 minutes.