Magic Link Authentication in Elixir Phoenix

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I want to show you a method of adding magic links to your project and I'm going to show you a GitHub project where I've laid out one commit with everything that you need I began this project by reading this post by John Elm it's a really good article it's very short you can go and read it yourself in like five minutes and it kind of goes over just the very basics of sending email tokens what I wanted to do was extend it I really like John's post but I wanted to take it a little bit farther I didn't want any passwords left in my project I wanted to figure out what's all the code I can remove from the Phoenix Geno generator that is related to passwords I wanted to get rid of all of it I also wanted one route for creating users and for logging them in so no separate register route I wanted One login route that handles login and registration now that is a stylistic choice you don't have to do it that way and I'll leave it as an exercise for you if you want to add in a registration page back but I'm going to walk you through what I have here on this project so I'm going to put the link in the description to this GitHub repo and I'm also going to put a link to an article on my blog that kind of summarizes a little bit of this information but if you come to this GitHub uh repo click this link that will take you to this Main commit here called how to add magic link authentication this has everything we need you can pretty much just use this as a reference and copy and paste code out of it if you want if you read my blog article in the description I also posted about how you can get a git patch from this commit and try to apply it directly to your project to a new project that way but I'm assuming that you've started a new project you've ran the Phoenix Geno generator and you've called the users context users and we're just going to start from that assuming you have a fresh slate so the first thing I want to point out is some of the files that can be deleted once we're done with this implementation you don't need to delete them first but just to point out when we're done we're not going to have this user confirmation instructions file we're not going to have user confirmation LIVE forgot password live all of these live views that the Phoenix Geno generator gives you we can get rid of we're also not going to have user registration live because we're going to combine that with user live which is the login live view we are however going to keep around user settings live but it does have a forgot password form in this file we're going to end up removing that form and we're just going to have the change email form but let's begin with the signin form so this is the signin form it it looks like this it's the exact same thing the generator gives us but we've removed the password so we can put in a new email and hit send me a link and we get a notice that we have been sent an email now let's look at the code so down here at this email input this is the main email input there was a password field here if you have just run the generator we can look at the GitHub diff and it looks something like this so there was a password field here and we have removed it so when you want to refer to these files to copy them into your own project again you can hit View file and copy the entire thing and just overwrite what you have or again you can refer to my blog post and there is a detail at the bottom about how you can generate a get patch but we're just going to run through the details so there's no password stuff in here just the email field and when we submit we're going to hit this send magic link handle event and I'm going to go past any live view specific details I'm assuming if you're watching this video you know something about live view but when the user submits that email form they're going to hit this function and it's going to call login or register user that is in the users context so we're going to go to the users's context here and we're going to look at that function just scroll down until we find it and it is right here so login a register user does exactly what it sounds sounds like it does it's going to look for a user with that email if it finds one it's going to try to log them in and if it doesn't find one it's going to create a new user and then send the login token and this is what handles that combining of the login and registration form this is how I wanted it to work if you don't want it to work that way you can have separate forms and you can have a login function and a register function and it's pretty easy to separate this so this function here build email token this is very similar to what the Phoenix Geno generator does for confirmation email tokens if you look at a project that uses Phoenix gen off you'll see something exactly like this for confirmation emails if we look at the token the user token file here the only thing that's changed here is we've added a new kind of context called it magic link and given it a different expiration time I'm not going to go over precisely how these tokens work because it's really an implementation detail of the generator not this specifically but basically they have a context with like one piece in the token and one piece in the email and they check against each other to make sure the token is valid the point is we generate a token here and then we call deliver login link here and we pass the token in here and here's the implementation of deliver login link I'm going to show you how it looks in the project not in a diff because the diff is a little messy but basically what I have here has a couple details from a previous video that I made about how to do HTML emails out of the box in Phoenix so don't worry about that if you're interested in that watch my previous video about it but just ignore that for now basically what we're going to get out of this render content function is just some HTML and text that's going to contain the token and I'll show you what that looks like so here I've opened Local Host Dev mailbox where we can look at these emails and I actually made two attempts to log in with this email and you can see on the first attempt I received the registration content and on the second attempt I received the login content so we do know that the login versus register is working but this is what the email looks like so when we click this link we'll be taken to the root path and it will say that we're logged in and if we refresh the page we can see our email on the top there so we know we're logged in and we can click log out go back to the signin page so we know it's working correctly just wanted to demonstrate to you what it looks like and real quick I also want to demonstrate changing your email so if we are logged in and we come to the settings page here we can change our email as well we can change it to something like example dodev hit change email and it says it's going to send us a new email let's go back to the dev mailbox take a look see open this up wide we do have the confirmation email we click on that and boom it has changed our email so I just wanted to show you that it does work um you can clone this project yourself and you can go through those steps and it should work but let's look at how some of those other pieces fit together so if we go to the router file you can see there's quite a few changes there is a lot of files deleted from the generator we don't have the register rout rout we don't have the login route I have renamed to login because that's just a a preference of mine and we've removed all the reset password stuff we've removed email confirmation stuff and note that the reason we've gotten rid of email confirmation here is because when we're creating the accounts we're going to create them with an unconfirmed email and then when they log in for the first time we're going to set their confirmed at timestamp so that's going to confirm them so that way we know any user with a confirmed at timestamp has logged in at least once so we could set up a recurring job to go through and find all the old users who have never logged in by seeing that they never have a confirmed at timestamp and then we could delete those users once a week or something like that so that's why in this method we don't need a confirmed live view or anything like that so we already looked at user Login Live that's the live view that's going to send the magic link but what is handling when the user clicks on the magic link well that's this route here login email token and then token in the pams and that's going to go to user session controller so let's take a look at that file it's right here and again you can copy this out of GitHub so there's three routes this file one of them is very self-explanatory it's just a log out route that I think is comes from this comes from the generator right when you create this file and then we've got this send magic link route and these are non- restful yes I know sometimes I do non- restful routes I don't think you should force yourself to stick to it all the time but this this non restful route here send magic link the reason that this exists is because in our live view in user login live in this form when we submit this form if the user did not have JavaScript turned on and they didn't have this action we wouldn't have a Handler for it it it needs an action to go somewhere without JavaScript so by having this action it lets the Forum work even if the socket is not connected but if we want to post to this form we need to be able to go to a controller we need to have a controller handle the result of this call if we want to do a get form it is possible to have the Live View kind of handle everything by putting a special case in Mount but for sending a email login token something that's actually going to change the database that's not the kind of thing you should do in a get request you should do it in a post request and that's why we need a separate controller that's going to handle the post request I wish live view had a way to do this directly in live view it would be really great if they added some controller features to live view but that's just how it works right now so that's why this is here but login with token this is what handles when the user actually clicks on the token in their email so what happens when they do that is it's going to try to find that user based on that token based on that bit of context in the token and if it does find them that means that the token was valid it was a good token so we're good to log them in and we can also confirm them at that time as we talked about earlier and then we can log them in and we can redirect them we can do whatever we want at that point if we we don't find a user by trying to look them up from that token that means the token was bad so we're not going to log them in we're going to redirect them to the login page in fact I also want to show you this user settings live this is the account route and the confirm email token route if we go to that file this has an example of what I was talking about earlier where you can handle git requests with pams in the p pattern matched parameter head of your functions in your live views this is an example right out of the generator so this file is basically straight out of the generator the only thing that we did is remove some password stuff so this is it in GitHub like you can see we've removed some passwords and and that's about it everything else is kind of the same another important thing to point out since we don't want passwords we can remove the hashed password field from the database and we'll do that in a separate migration and once we have that migration we can also remove the two password fields from the ectos schema for users so that's pretty much the gist of the changes if we just scroll through here in the context for instance there's a lot of deleted functions most of them are just having to do with passwords there's a couple changes here and there there's the changes to the password fields on the schema there's the email sending changes obviously we have some different looking emails now there's the new context for tokens I have also in my code changed a couple names of routes I prefer accounts to user settings there's the changes to the user session controller that send magic link function we looked at that function that handles receiving the token we have obviously removed a number of live views that we don't need anymore we've got the live view that handles sending the magic link we have the user settings file which has our change email form we have the changes to the router which are removing several paths that we don't use the login route has changed from users login to login and we have the magic link handling route and we just have a couple other renames here and there and then the migration and then a number of tests some remove tests we've Chang some tests there's a whole bunch of test changes in here so how can you go about using this in your own project I didn't make a library I didn't write a generator or anything like that I gave you this GitHub so I think the best way that you can interact with this is by going down to the commit itself copying the commit then go to your terminal and I'm going to assume that you have a new project where you have ran the Phoenix Geno generator and you've named the context users as I have done here but if you named it something else you can change the patch I'm going to show you how to create the patch first so what you can do is you have to have WG installed but if you have WG installed you can paste that commit URL and then just add. patch to the end of it and also we can rename the file when we save it and what that file it's going to look like when we've downloaded it is it's going to turn that commit into a git patch that we can then apply and if you haven't worked with get patches before it's very easy I'm going to show you how to do it but before we can do that we're probably going to need to change the name of the repo in the patch so if we look at the patch we can see the project is is called example and of course there's an example web module and an example module and we would need to change that to match our project so let's assume our project is using something like uh app now this is as you can see I wrote this earlier but what we can do is we can just use said to change the patch in place so this is the current version on the left and then we're going to change it to app and because it shows up lowercase and uppercase we need to change it in both ways so let's just say it's going to be like my app as the module name and my underscore app and the good part about this is when we run this and and look at the patch we can see that it changed the the example module and the example web module because we didn't specify so we just Chang them both so there you go that's how you can change the project name of this patch and then we can apply it it's really easy there's a command called get apply and then we can specify the patch and there's two commands two flags you may be interested in one of them is dash3 and if you do this you're going to attempt a three-way diff against your repo and the patch sometimes that works really good if there is conflicts that it thinks it can resolve or that it thinks are resolvable then you can resolve them in that manner if there's files that don't that get doesn't think exists in the working directory however this doesn't always work another thing you can do instead is reject and if you do this you will end up with a bunch of files with like do reject on the end of them if they are files that don't have a matching file in your working directory so that's the nice part about this D- reject we'll try to apply everything it can and anything it can't will be sitting there on your file system and you can go take a look at it and fix the problem yourself basically so that's pretty much it I didn't really want to give you a super detailed super exhaustive step through every bit of code here I think if you're watching this video you are capable of going and reading some of this yourself I just wanted to tell you about it I'm planning on a couple projects that I want to use magic links for and I just wanted a quick way to start them to have a example that I can copy and paste code out of so that's exactly what this is now I do think it can be improved a little bit it would be nice to have an example of doing some ooth for instance I might add that in a second version another thing that might be nice is logging in on different different devices now this is one thing that I think is the biggest problem with magic link authentication when you get the link and you open your phone and you click the link on your email client on your phone and then you're logged in on your phone it's a massive pain there are ways around it one of the things you can do is pop up a little question when the user clicks the email and says hey do you want to log in on this browser or do you want to log in on your other tab I might make another video adding that on at a later date or if you have anything you'd like to see let me know it would definitely be possible to make a generator for this if you wanted to if there's some interest in that it would definitely make the workflow a little simpler and that's something that could be explored but let me know in the comments if this was useful to you
Info
Channel: Andrew Stewart | src_rip
Views: 897
Rating: undefined out of 5
Keywords: elixir, phoenix, magic links, programming, authentication
Id: eM8vl7pgRJM
Channel Id: undefined
Length: 21min 57sec (1317 seconds)
Published: Thu Dec 28 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.