Add Magic Link Authentication
To use magic for authentication you’ll first need a set of credentials. You can get those by registering at https://magic.link/.
Magic offers a free tier for the first 100 recurring users with options to upgrade. Once you have created an app and have both secret and test keys you are ready for next steps. Open up our NextJS project in your terminal and type:
Next up let’s import the magic package we have just installed into our AuthContext.
Now let’s also add our public key that we got from magic to our urls.js file so we can use it later and import it inside of our AuthContext.
To connect with magic let’s declare a variable called “magic” outside our AuthContext. We do this because we are going to re-declare it later and use it inside of our authentication functions.
Next let’s use a useEffect hook inside of our AuthContext to set up magic on initial application load.
And that’s it, our magic authentication system is ready to be implemented inside of our login and logout functions, so let’s do that next. Let’s start by updating our login function.
Now let’s also update our logout function.
We can now finally test it out! But, there is one issue. If you try refreshing our user will not be persisted. This is something we are going to fix next.
Finally, to persist user login between refresh, let’s add checkUserLoggedin function.
And call it in the useEffect hook to make it run on the initial application load. Now our user should persist on refresh
Finalizing the look of Login page
Let’s add some style to our page by creating a new file called Login.module.css inside of our styles folder and add some basic styling.
And that’s it for our styles in the Login.module.css file. Now let’s import the styles to our login page. And this is how our login page should look like now.
You’ll also notice that displaying the whole email address breaks into multiple lines which we do not want. So instead of displaying the whole email address, let’s instead display an icon inside our Header component.
And so this is how our Header component should look now!
Connecting Magic to Strapi
Now that your user can log in to the front-end, we can use Magic to make authenticated requests to Strapi. In order to do that we’ll have to install the Strapi Plugin Magic and then customize one file in Strapi’s code.
This will make it so that whenever we make an authenticated request, Strapi will create or find the proper user, seamlessly and securely connecting the frontend and the backend.
First, shift to the Strapi Terminal, install the Strapi Plugin Magic by typing:
Then rebuild strapi with:
Then restart strapi by typing:
By refreshing localhost:1337/admin you’ll notice a new entry in the plugins section.
You can store your Magic Secret Key which you got from magic, it will be used by the plugin to log users in.
Next, we’ll need to override the default permissions policy. The policy is used to determine who the current logged in user is.
If you want to learn more, there’s a full video just for this plugin detailing the installation steps and features even further.
To customise Strapi’s behaviour, open extensions/users-permisisons/config.
Create a new folder called policies inside extensions/users-permissions and a new file called permissions.js file inside policies.
Next, you’ll have to copy and paste the default version of this file, which you can find at any time on Strapi’s GitHub.
Visit Strapi’s Github at github.com/strapi/strapi.
Packages -> strapi-plugin-users-permissions.js
Or visit this link
This change makes it so that if you make a request to Strapi, while using a Valid Magic Generated Bearer Token, Strapi will either create or add the user with the email that was used to log in with magic.
This connects the front-end and the back-end in a very seamless way.
To show you what I mean, let’s work on the Orders Collection Type that we’re going to be displaying to our user and that we will be processing through Stripe in the future.
Testing the Connection
In order to make authenticated requests with Magic, you’ll need to retrieve a bearer token.
Let’s add this functionality to our AuthContext so we can test the Magic and Strapi Integration.
To start, let’s create a function called getToken inside our AuthContext to retrieve the bearer token from magic.
And now call it inside of the checkUserLoggedIn function. We do this because we want to console log our unique token, so we can test it out on Postman.
Open up the console in your browser and refresh the page. If everything worked you should see your unique token getting printed in your console.
Now using this token let’s make a request on Postman to our back-end. Don’t forget to set the type to bearer token in the “Authorization” tab and copy in the token.
Let’s create orders in strapi with the following fields: status (enum: paid unpaid), total (number decimals) and relationships with checkout_session (text), users_permissions_user -> User, product -> Product ( a single product can have / be in many orders).
Next, let’s open up orders for authenticated users.
This means that non logged in users will not be able to retrieve the orders.
PRIVACY DISCUSSION HERE:
I could just use a filter, but the problem is that it would allow other users to fetch orders that don’t belong to them. The simplest way is to override the default find and findOne Controllers so that a user can only find their own Orders. You can do so by opening up /api/orders/
Create a Test Product. Make sure to publish it.
Attach the order to the user you have The user has been automatically created by Strapi Plugin Magic when you first entered the email and authenticated.
Now create a second order, without a user.
If you get an ‘Invalid token’ error the reason might be that the token expired, so retrieve a new one by refreshing your application and copying it from the console.
Make the GET request and you’ll see you have access to both orders. This is a privacy violation that we’re going to fix next. Because we don’t want users to see each other's orders, ONLY the orders that are associated with that specific user.
Show me only my orders
We can show a user only their orders by overriding the default controller inside /api/order/controllers/order.js file that strapi generates.
First, we’ll import a util function that comes shipped with strapi.
Next we’ll override the find function with our own logic with privacy in mind.
And for the end, we’ll also override findOne function that will return a single order by provided id, but since we have privacy in mind we are only going to return if the passed order id matches the order id and user matches the order’s user.