appwrite / appwrite

Your backend, minus the hassle.
https://appwrite.io
BSD 3-Clause "New" or "Revised" License
45.31k stars 4.01k forks source link

🐛 Bug Report: email verification (confirmation) does not trigger any account subscription event #5095

Closed fguerzoni closed 1 year ago

fguerzoni commented 1 year ago

👟 Reproduction steps

I was trying to automate the transition from the 'send a verification email' page to the main internal page (reserved to full logged in users). When the user sends the confirmation email verification from the page opened by the link in the verification email the user account state gets updated to reflect the emailVerification flag change from false to true. So I thought to subscribe to the account object and to get notified on the client app of such a change. The whole mechanism works fine when I directly press the verify/unverify button inside the user profile but it doesn't work when the account is updated by the email confirmation. I subscribed to the account object from the 'send verification email' page that stands still because the process goes on on the page opened by the email link.

👍 Expected behavior

To get notified on the client app, which is already subscribed to the account object, when the emailVerification flag is updated by the email confirmation sent from the client app itself. It should work exactly as when I press the verify / unverify from the button inside the user account

👎 Actual Behavior

It actually doesn't trigger any event and the client app, already subscribed to the account object, doesn't get notified

🎲 Appwrite version

Version 1.2.x

💻 Operating system

Linux

🧱 Your Environment

The client app is developed with Vue3 and uses appwrite sdk at release 10.2.0

👀 Have you spent some time to check if this issue has been raised before?

🏢 Have you read the Code of Conduct?

stnguyen90 commented 1 year ago

@fguerzoni, thanks for creating this issue! 🙏🏼 What channel did you use for your subscribe code?

fguerzoni commented 1 year ago

@stnguyen90 The channel is "account". Regards

LyVanBong commented 1 year ago

I am also encountering a problem with the SMTP configuration of the Outlook Office 365 email. Has anyone encountered this issue before? Can anyone help me with this, I would greatly appreciate it. Thank you.

stnguyen90 commented 1 year ago

@fguerzoni, I think I see what's going on....I think the confirmation API call is made without a session so the user's context isn't used and so the realtime event isn't sent to the user. I tested by making the confirmation API call manually while authenticated with the fallback cookies header and the event came through, but when I did it in an incognito window without the fallback cookies header, it did not come through.

Here's where the user id is set in preparation to send to the realtime server, but I'm pretty sure $user->getId() is null here:

https://github.com/appwrite/appwrite/blob/661581a7f362f7aa26ba8e243b8542a3f2c9a9b4/app/controllers/api/account.php#L2298

and it should probably be $profile->getId() instead.

stnguyen90 commented 1 year ago

I am also encountering a problem with the SMTP configuration of the Outlook Office 365 email. Has anyone encountered this issue before? Can anyone help me with this, I would greatly appreciate it. Thank you.

@LyVanBong, it sounds like you're having a different problem than this issue describes. If you're having problems configuring SMTP, I would recommend looking at the Email Delivery docs. If you're still having trouble, please join us on Discord.

fguerzoni commented 1 year ago

@stnguyen90 thank you for the detailed analysis You let me catch an important point that I previously didn't consider at all. I usually do every development in Chrome on my desktop but my primary browser is FF. So it happened that I sent the verification confirmation either from FF (tied to email client) or from Safari on mobile phone: but never from the same Chrome where the user is logged in. So there's no fallback cookie at all in place, as you brilliantly detailed.

I tested your idea doing copy&paste of the link from the confirmation email on the Chrome where the user is logged in. And the webapp gets notified! But the data I received are different both in the event and payload section:

{"events":["users.635170d3289714140b14.verification.63e6bfc86d12293584a2.update","users.*.verification.*.update","users.635170d3289714140b14.verification.*.update","users.*.verification.63e6bfc86d12293584a2.update","users.635170d3289714140b14.verification.63e6bfc86d12293584a2","users.*.verification.*","users.635170d3289714140b14.verification.*","users.*.verification.63e6bfc86d12293584a2","users.635170d3289714140b14","users.*"],"channels":["account","account.635170d3289714140b14"],"timestamp":"2023-02-10 22:06:45.497","payload":{"$id":"63e6bfc86d12293584a2","$createdAt":"2023-02-10T22:06:00.447+00:00","userId":"635170d3289714140b14","secret":"243553edbaf9c0bfc7c8d9e7623b091cce99e25ee18ffe62580c05816e116964", "expire":"2023-02-17T22:06:00.446+00:00"}}

from the data I received when manually changing the verification flag from the user profile in the admin dashboard:

{"events":["users.635170d3289714140b14.update","users.*.update","users.635170d3289714140b14.update.verification","users.*.update.verification","users.635170d3289714140b14","users.*"],"channels":["account","account.635170d3289714140b14"],"timestamp":"2023-02-10 22:10:22.631","payload":{"$id":"635170d3289714140b14","$createdAt":"2022-10-20T16:01:23.300+00:00","$updatedAt":"2023-02-10T22:10:22.604+00:00","name":"filippo","password":"dropped","hash":"argon2","hashOptions":{"memoryCost":2048,"timeCost":4,"threads":3,"type":"argon2"},"registration":"2022-10-20T16:01:23.300+00:00","status":true,"passwordUpdate":"2022-10-20T16:01:23.300+00:00","email":"dropped","phone":"","emailVerification":true,"phoneVerification":false,"prefs":[]}}

In the latter I've got the emailVerification value while in the former that value is missing. The latter seems to be more useful than the former. The events seem to be swapped comparing the data.

What do you think? regards

stnguyen90 commented 1 year ago

It looks like the APIs return different things in the Users API vs the Account API:

That's why you're seeing a different payload from the Realtime API.

fguerzoni commented 1 year ago

Thank you very much for the explanation. Very helpful.

Pranav2612000 commented 1 year ago

Hi @stnguyen90 I'll like to work on this issue. Like you mentioned replace $user->getId() by $profile->getId() should solve the issue. But I still think this'll be a good issue to start contributing to the project.

stnguyen90 commented 1 year ago

@Pranav2612000, assigned! Thanks for your interest! 🙏🏼

Pranav2612000 commented 1 year ago

@stnguyen90 I was able to set up the development environment and play out a bit. I have some questions, it would be great if you could help me out

Thanks.

fguerzoni commented 1 year ago

About the second question I think the easiest way is to setup the email sending in your appwrite. It's quite easy. I've created a mailgun account and I've setup a sender domain (mg.xxx.yyy below) with the mailgun dashboard. Then I've updated the following keys in the .env file inside the appwrite directory:

_APP_SMTP_HOST=smtp.eu.mailgun.org
_APP_SMTP_PORT=587
_APP_SMTP_SECURE=
_APP_SMTP_USERNAME=postmaster@mg.xxx.yyy
_APP_SMTP_PASSWORD=zzz

There's a free trial available with mailgun you can subscribe to. Thanks and regards

Pranav2612000 commented 1 year ago

I've done the above setup @fguerzoni But I still don't get an email when a new user is created r. Is there anything else that I need to do that I am possibly missing?

fguerzoni commented 1 year ago

@Pranav2612000 The email get sent automatically by Appwrite just in the case you trigger the "create email verification" (https://appwrite.io/docs/client/account?sdk=web-default#accountCreateVerification) To trigger some custom logic at user creation you have to implement and register a so called 'function' (https://appwrite.io/docs/functions) with correct settings (have a look at the attached screenshot) settings

Pranav2612000 commented 1 year ago

Nope. Still not getting the emails. Will try to debug again tomorrow. Meanwhile, I was able to figure out the what the sessionId and userId for the email verification API ( https://appwrite.io/docs/client/account?sdk=rest-default#accountUpdateVerification )

But calling that API results in a User with requested ID could not be found error. Any idea what may be happening?

fguerzoni commented 1 year ago

@Pranav2612000 Every time you change the .env file you shall also run: docker compose up -d More details at the docs: https://appwrite.io/docs/email-delivery

Pranav2612000 commented 1 year ago

Yup. I was doing that. In the worker-mails container I can see the cannot connect to SMTP error. Will need to check what the issue is.

stnguyen90 commented 1 year ago

@Pranav2612000

Can a possible fix be to use the $userId variable which we already have?

Yes.

I was able to create a new user, but I didn't receive any email to verify the account, and couldn't find a button to trigger verification emails as well. How do I do that? If that's not possible, what's the alternative easiest way to reproduce the issue?

You can't Create an Email Verification from the Appwrite Console. You'll need to trigger it with some client SDK.

Meanwhile, I was able to figure out the what the sessionId and userId for the email verification API

You mean secret?

But calling that API results in a User with requested ID could not be found error. Any idea what may be happening?

You're getting that error because the User ID you passed is invalid. See:

https://github.com/appwrite/appwrite/blob/661581a7f362f7aa26ba8e243b8542a3f2c9a9b4/app/controllers/api/account.php#L2274

Pranav2612000 commented 1 year ago

I have a PR ready but still not able to test it out completely. Here's my workflow - I've started appwrite by running docker-compose up -d

I'm stuck after this. Trying to call the email verification API fails with User (role: guests) missing scope (account)

stnguyen90 commented 1 year ago

@Pranav2612000, it might be best create a support post on Discord.