Skip to content
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

Email client previewing links expires confirmation/reset/invite tokens #368

Closed
awalias opened this issue Feb 2, 2022 · 9 comments
Closed
Labels
bug Something isn't working

Comments

@awalias
Copy link
Member

awalias commented Feb 2, 2022

report from a user that some email clients are doing link scanning/preview and consuming the verification tokens - rendering them stale for the users

one approach is to check the UA for bots, scanners, and crawlers to GET requests to /verify to prevent this
checking UA doesn't work for Mac mail client

@awalias awalias added the bug Something isn't working label Feb 2, 2022
@awalias
Copy link
Member Author

awalias commented Feb 3, 2022

one workaround I thought of is change the email template to point to a new page in your app with a big button “Accept Invite” and pass the ConfirmationURL as a query param.

e.g.

<h2>You have been invited</h2>

<p>You have been invited to create a user on {{ .SiteURL }}. Follow this link to accept the invite:</p>
<p><a href="{{ .SiteURL }}/accept-invite?invite_link={{ .ConfirmationURL }}">Accept the invite</a></p>

Then the button takes the url from the query param as it’s href

WARNING: the code in your app that plucks the ConfirmationURL out of the query param should validate it before setting it as the href of the button (otherwise it’s vulnerable to CSRF)

also validate that the url from the query matches the https scheme and it is the supabase domain. else you might also be exposed to dom-based xss attacks (where someone sends ?https://app?confirmationURL=javascript:alert(1) for example

@awalias awalias changed the title Bots expiring email links Email client previewing links expires confirmation/reset/invite tokens Feb 3, 2022
@leynier
Copy link

leynier commented Feb 6, 2022

This error is happening to me, maybe the workaround works well, but the user experience will be not the best. Is there an idea about what way follow to solve the issue? Thanks in advance.

@kangmingtay
Copy link
Member

kangmingtay commented Feb 8, 2022

Hey @leynier, we're currently working on sending both the confirmation url and an OTP for all links. That way, you can choose to omit the ConfirmationURL from the template and use the OTP to verify your users instead. This would work similar to the phone auth verification.

The default template will be something like the following:

<h2>Confirm your email</h2>

<p>Follow this link to confirm your email:</p>
<p><a href="{{ .ConfirmationURL }}">Confirm your email address</a></p>
<p>Alternatively, enter the code: {{ .Token }}</p>

Let know me know if this helps!

@leynier
Copy link

leynier commented Feb 9, 2022

Hey @leynier, we're currently working on sending both the confirmation url and an OTP for all links. That way, you can choose to omit the ConfirmationURL from the template and use the OTP to verify your users instead. This would work similar to the phone auth verification.

The default template will be something like the following:

<h2>Confirm your email</h2>

<p>Follow this link to confirm your email:</p>
<p><a href="{{ .ConfirmationURL }}">Confirm your email address</a></p>
<p>Alternatively, enter the code: {{ .Token }}</p>

Let know me know if this helps!

Yes, that will help. Thanks a lot.

@kangmingtay
Copy link
Member

just an update, we've added this functionality to the latest version of gotrue-js as well, gonna close issue for now and feel free to let me know if there are any issues!

@haydn
Copy link

haydn commented Apr 11, 2022

@kangmingtay We've hit this problem (the customer has some kind of security in place that accesses all the links in an email before it even makes it to their inbox). The solution here sounds great, however, we're using POST /admin/generate_link and sending our own emails instead of using the built-in emailing. Is there a way we can access the {{ .Token }} when using POST /admin/generate_link? That endpoint appears to only return the {{ .ConfirmationURL }} as action_link.

@kangmingtay
Copy link
Member

Hey @haydn, right now, there isn't an easy way to get the {{ .Token }} when using POST /admin/generate_link but you can extract it from the url link returned by parsing the token query param

@haydn
Copy link

haydn commented Apr 18, 2022

@kangmingtay Thanks for the info! What is that token in the database? Could I grab it directly from there? I guess I'm wondering if I even need to be using the POST /admin/generate_link endpoint for this setup.

@kangmingtay
Copy link
Member

@haydn yup you could

signup / invite -> confirmation_token
recovery / magiclink -> recovery_token
email change -> email_change_token_current / email_change_token_new
phone change -> phone_change_token
reauthentication for password updates -> reauthentication_token

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants