Authenticate a Nuxt.js App Using a Magic URL and Mailgun
Tags: appwrite, typescript, javascript, nuxt
Published: 2022-10-28 12:19:35

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](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) magic URL.

## GitHub

Check out the complete source code [here](https://github.com/MoeRayo/magic-url).


## Prerequisites

Understanding this article requires the following:

- Installation of Node.js
- Basic knowledge of TypeScript
- Docker [installation](https://www.docker.com/get-started/)
- Basic understanding of Simple Mail Transfer Protocol (SMTP)
- An Appwrite instance; check out this [article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) on how to set up an instance locally or one-click install on [DigitalOcean](https://marketplace.digitalocean.com/apps/appwrite) or [Gitpod](https://gitpod.io/#https://github.com/appwrite/integration-for-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:
![Nuxt application scaffolding options](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elxl362tphyl2dhr4ffw.png)

We can start our Nuxt3 application by running the following command:

```javascript
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:

```javascript
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](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) if we don’t have one.


![Appwrite Create a project interface](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hcsecifvluf4k5e2ub6m.png)

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 magic URL settings annotation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vdmd2mjbo1k14hhmhx5y.png)

The inner page allows us to copy the **Project ID** and **API Endpoint** for use in our Nuxt application.

![The project and API endpoint page of the created project on the Appwrite console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i9s75n3rnor8r42xdblo.png)

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:

```javascript
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](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol), sometimes referred to as an application used in sending and receiving emails. There are several SMTP services like [SendGrid](https://sendgrid.com/) and [Mailgun](https://www.mailgun.com/), but in this article, we will use Mailgun - Appwrite also supports other emailing services.

We will start by creating an account with [Mailgun](https://www.mailgun.com/). 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:

![Annotations showing how to navigate Mailgun dashboard to get credentials](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwplnhts684ess0bgdgc.png)

Clicking on **SMTP** brings the Mailgun credentials as shown below:


![The SMTP credentials on Mailgun](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9fab0od54swkz1h0d28x.png)

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:


![The .env and docker-compose files in the installed Appwrite folder on our computer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o2bb0ms4onm45ul72mmw.png)

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:

```javascript
_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:

```javascript
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:

![Annotated option selected for creating a platform for a web app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/muiilt34fu678ykyzuf6.png)

We will add a distinct name for the platform with a hostname. 

![The create platform form on Appwrite console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ikn0ugat8cch8rxezlsb.png)


The hostname represents the Appwrite domain added during the Appwrite installation - in our case, `localhost` was used like so:

```javascript
_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:

```javascript
<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 the `sendMagicURL` function within our `methods` object
- The `sendMagicURL` function access the `createMagicURLSession` on Appwrite’s `account` 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
- 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:


![The home page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/egjm6kiicdwn0a4128fh.png)

## 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:

```javascript
<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 our `methods` which creates a new `URLSearchParams` object which returns a URL querying string
- Returned the values of the `userId` and `secret` using `urlParams.get()` method 
- Accessed the `updateMagicURLSessionon` Appwrite’s `account` method, which takes in the values of the `userId` and `secret`
- Redirected our application to the landing page represented with `/landing` after successful verification

Our `pages/verify.vue` will look like the below before verification:

![The verification page UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ihtiop52dnyt9simjrg.png)

## 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:

```javascript
<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:

![The landing page UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tswc7j1kgys4fj969a7c.png)

We have successfully implemented a Magic URL login using Appwrite, and our application will look like the gif below:


![Our final implementation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wadbdg5s2d8idd4rk83g.gif)


## 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:

- [Create a local Appwrite instance in 3 steps](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) 
- [Appwrite Doc - Magic URL](https://appwrite.io/docs/client/account?sdk=web-default#accountCreateMagicURLSession)