Authentication involves checking and ascertaining the genuineness of a user, i.e., verifying if the person trying to gain access to a product is the right person. Authentication has evolved from the traditional method of manually using passwords to using magic Uniform Resource Locators (URL).
A Magic URL is a one-time passwordless authentication URL sent to a secure destination, most times the email, from where the user can access it to log into the application. The magic URL removes the user's effort to put their password into an application manually. Instead, a securely generated link is sent to the user’s account, and opening this magic link will subsequently sign the user in to access the application.
This article will discuss how to authenticate a Nuxt application using Appwrite’s magic URL.
GitHub
Check out the complete source code here.
Prerequisites
Understanding this article requires the following:
- Installation of Node.js
- Basic knowledge of TypeScript
- Docker installation
- Basic understanding of Simple Mail Transfer Protocol (SMTP)
- An Appwrite instance; check out this article on how to set up an instance locally or one-click install on DigitalOcean or Gitpod
Creating a Nuxt project
Use npx create-nuxt-app <project-name>
to create a new Nuxt project.
The process of scaffolding the project would provide a list of options, which should look like this:
We can start our Nuxt3 application by running the following command:
cd <project name>
npm run dev
Nuxt will, in turn, start a hot-reloading development environment that is accessible by default at http://localhost:3000
.
Installing Appwrite
To use Appwrite in our project, we will install the Appwrite web software development kit (SDK) from the command line, like so:
npm install appwrite
Creating an Appwrite project
To create a new project, start up the Appwrite instance on your machine and navigate to the specified hostname and port http://localhost:80
. Next, we need to log in to our account or create an account if we don’t have one.
The project dashboard becomes visible on the console after the project creation. We can access the inner page from the Settings tab at the top of the page.
The inner page allows us to copy the Project ID and API Endpoint for use in our Nuxt application.
We will then proceed to create an init.js
file in our Nuxt application’s root directory to initialize the Appwrite Web SDK by adding the code block below:
import { Client, Account } from "appwrite";
export const client = new Client();
export const account = new Account(client);
client
.setEndpoint('http://localhost/v1') // Your API Endpoint
.setProject('***') // Your project ID
;
Setting up Mailgun as an SMTP
Simple Mail Transfer Protocol (SMTP) is a protocol, sometimes referred to as an application used in sending and receiving emails. There are several SMTP services like SendGrid and Mailgun, but in this article, we will use Mailgun - Appwrite also supports other emailing services.
We will start by creating an account with Mailgun. We can then log into our Mailgun dashboard to get hold of our credentials for usage on Appwrite. From our dashboard, we will navigate to Sending > Overview, from where we can select SMTP as seen below:
Clicking on SMTP brings the Mailgun credentials as shown below:
We take note of these credentials as we need them in Appwrite.
Updating our Appwrite .env
with Mailgun credentials
Installing Appwrite on our computer makes a docker.comopose.yml
and a .env
environment file available, as seen below:
We are at liberty to customize the .env
to meet our server needs. To use Mailgun SMTP, we will need to update some properties within the Appwrite env
, like so:
_APP_SYSTEM_EMAIL_NAME=Name
_APP_SYSTEM_EMAIL_ADDRESS=example@outlook.com
_APP_SMTP_HOST=smtp.mailgun.org
_APP_SMTP_PORT=587
_APP_SMTP_SECURE=tls
_APP_SMTP_USERNAME=postmaster@sandbox2a88e2********b40.mailgun.org
_APP_SMTP_PASSWORD=f13cd0*******e93193
_APP_SYSTEM_EMAIL_NAME=Name
: Denotes senders’ name
_APP_SYSTEM_EMAIL_ADDRESS
: Refers to senders’ email addresses.
_APP_SMTP_HOST
: The SMTP hostname, which in this case is smtp.mailgun.org
_APP_SMTP_PORT
: SMTP Transmission Control Protocol (TCP) port represented as 587
_APP_SMTP_SECURE
: Represented with tls to denote the SMTP connection protocol
_APP_SMTP_USERNAME
: SMTP’s username
_APP_SMTP_PASSWORD
: SMTP password
After setting the above and saving our file, we will need to restart our Appwrite container using the command below in our terminal, after navigating into the folder that contains the docker-compose
file:
cd Appwrite // navigate into the Appwrite folder
docker-compose up -d --remove-orphans
With this done, we can navigate to our Appwrite console to add a new platform to use magic URL on Appwrite.
Adding the magic URL platform on Appwrite console
To use Appwrite’s magic URL service, we will need to add a new platform within the Appwrite application we have created. To do this, we will navigate to the project we want to use the magic URL. We will then create a New Web App platform like so:
We will add a distinct name for the platform with a hostname.
The hostname represents the Appwrite domain added during the Appwrite installation - in our case, localhost
was used like so:
_APP_DOMAIN=localhost
_APP_DOMAIN_TARGET=localhost
The domain name used depends on what we set in the .env
file, and this domain should always match the base URL of the application.
Getting the magic URL
Now we are ready to begin building our application. To do this, we will navigate into our application’s pages/index.vue
and edit the file to the code below:
<template>
<div class="bg-lightest-blue vh-100 pa3 tc">
<h2 class="ttc">Magic URL with Appwrite</h2>
<div class="br3 bg-navy ba near-white b--black-10 shadow-3 w-100 w-60-m w-30-l mw6 center mt5 ph4 pv4 h5">
<p class="f3">Click on this button to get the magic URL</p>
<button class="link br3 pv2 ph2 mt4 dib black fw6 bg-white ba b--navy pointer inline-flex items-center hover-bg-lightest-blue" @click="sendMagicURL">
<span class="f4 ml2 pr2">Get magic URL</span>
</button>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import {account} from '~/init'
import { ID } from 'appwrite';
export default Vue.extend({
name: 'IndexPage',
methods: {
sendMagicURL: async function () {
try {
await account.createMagicURLSession(ID.unique(), 'example@email.com', 'http://localhost:3000/verify')
alert('Magic URL sent')
} catch (error) {
console.log(error)
}
}
}
})
</script>
The code snippet above performs the following functions:
- We added a button in our
<template>
, which calls thesendMagicURL
function within ourmethods
object - The
sendMagicURL
function access thecreateMagicURLSession
on Appwrite’saccount
method - The
createMagicURLSession
takes in two required parameters:-
userId: A unique Id is gotten by accessing Appwrite’s
ID
method. - email: The email we would like to send the magic URL to
-
userId: A unique Id is gotten by accessing Appwrite’s
- The third optional parameter in the
createMagicURLSession
function is the URL we would like to redirect the user to after clicking on the magic URL. This URL must be the hostname added to our Appwrite project platform.
At this point, we will have an email in our inbox that will expire in an hour. Our pages/index.value
will also look like the below:
Verifying the magic URL
The magic URL sent to the email address added will have a userId and secret key for creating a session, which we will access to complete our login process. To do this, we will create a new file named pages/verify.vue
, which the user gets redirected to after clicking the email in the inbox. We will edit the page by adding the code below:
<template>
<div class="bg-lightest-blue vh-100 pa3 tc">
<h2 class="ttc">Magic URL with Appwrite</h2>
<div class="br3 bg-navy ba near-white b--black-10 shadow-3 w-100 w-60-m w-30-l mw6 center mt5 ph4 pv3 h5">
<p class="f3">Verify Magic URL</p>
<p>To complete this session, please verify your magic URL by clicking the verification button.</p>
<button class="link br3 pv2 ph2 mt3 dib black fw6 bg-white ba b--navy pointer inline-flex items-center hover-bg-lightest-blue" @click="verifyMagicURL">
<span class="f4 ml2 pr2">Verify magic URL</span>
</button>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import {account} from '~/init'
export default Vue.extend({
methods: {
verifyMagicURL: async function () {
const urlParams = new URLSearchParams(window.location.search);
const userId : any = urlParams.get('userId');
const secret : any = urlParams.get('secret');
try {
await account.updateMagicURLSession(userId, secret);
alert("Magic URL verified")
window.location.href = '/landing'
} catch (err){
console.log(err)
}
}
}
})
</script>
From the code snippet above, we were able to verify our account by doing the following:
- Added a
verifyMagicURL
function within ourmethods
which creates a newURLSearchParams
object which returns a URL querying string - Returned the values of the
userId
andsecret
usingurlParams.get()
method - Accessed the
updateMagicURLSessionon
Appwrite’saccount
method, which takes in the values of theuserId
andsecret
- Redirected our application to the landing page represented with
/landing
after successful verification
Our pages/verify.vue
will look like the below before verification:
Creating the landing page
After successfully verifying the magic URL, we will redirect the user to a landing page. To achieve this, we will create a pages/landing.vue and add the code below:
<template>
<div class="bg-lightest-blue vh-100 pa3 tc">
<h2 class="ttc">Magic URL with Appwrite</h2>
<div class="br3 bg-navy ba near-white b--black-10 shadow-3 w-100 w-60-m w-30-l mw6 center mt5 ph4 pv3 ">
<p class="f2">Verification successful 🎉🎉</p>
<p></p>
</div>
</div>
</template>
At this point, our landing page will look like the below:
We have successfully implemented a Magic URL login using Appwrite, and our application will look like the gif below:
Conclusion
One of the fantastic features Appwrite provides is the magic URL that simplifies authentication for users without the hassle of the user trying to remember their passwords. This post discusses how to implement the magic URL during authentication.
These resources might be helpful:
Top comments (1)
Clear and precise, thanks! 🙏🏻