Introduction

This guide will help you to create a completely headless sign-up/sign-in with email while issuing and verifying an OTP for the user. It follows three simple steps, creating the email verification, verifying the OTP, and getting the JWT.

Tutorial

Basic UI

First though, let’s create a basic React component to help us handle the UI:

import React, { useState } from 'react';

const EmailSignup = () => {

    const DYNAMIC_ENVIRONMENT_ID = "YOUR_ENVIRONMENT_ID";

    const [email, setEmail] = useState("");
    const [verifying, setVerifying] = useState(false);
    const [OTP, setOTP] = useState("");
    const [UUID, setUUID] = useState("");
    const [JWT, setJWT] = useState("");

    const sendEmailVerification = async () => {};
    const verify = async () => {};

    return (
        <div>
            <h1>Signup with Email</h1>
            <input
            type="text"
            onChange={(e) => setEmail(e.target.value)}
            placeholder="Enter your email"
            value={email}
            />
            <button onClick={() => sendEmailVerification()}>Submit</button>
            {verifying && (
            <div>
                <input
                type="text"
                onChange={(e) => setOTP(e.target.value)}
                placeholder="Enter your OTP"
                value={OTP}
                />
                <button onClick={() => verify()}>Verify</button>
            </div>
            )}
            {JWT && <p>Your JWT is: {JWT}</p>}
        </div>
    );
}

We’re creating a few state variables to help us keep track of the user’s email, the OTP, the verificationUUID, and the JWT. We’re also creating a couple of (currently empty) functions to handle the email verification and the OTP verification.

You might be wondering what the UUID variable is for. When you create an email verification, we return a verificationUUID that you must pass into the API along with the OTP itself so that it’s correctly verified.

Lastly but most importantly, there’s a variable called DYNAMIC_ENVIRONMENT_ID. We will need this to populate the URLs for the API calls. You can find your environment ID in the Dynamic dashboard.

OK, let’s fill in the empty functions now, going step by step:

Create an email verification

You will be interacting with the emailVerification endpoint for this. This will send an email to the user with a One Time Password so they can verify their email address.

You can find the full reference for the endpoint in the link above, but the main thing you need to pass is the email address of the user. We’ll edit our sendEmailVerification function like so:

const sendEmailVerification = async () => {
  setVerifying(true);

  const options = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ email: email }),
  };

  fetch(
    `https://app.dynamicauth.com/api/v0/sdk/${DYNAMIC_ENVIRONMENT_ID}/emailVerifications/create`,
    options
  )
    .then((response) => response.json())
    .then((response) => {
      setUUID(response.verificationUUID);
    })
    .catch((err) => console.error(err));
};

Verify the OTP

With the above step complete, as long as the email address is valid, the user will receive an email with an OTP. They will enter the OTP in the UI, and we will verify it once they hit the “Verify” button.

To verify the OTP, the next call will be to signIn endpoint, which you can find here. You will need to pass the OTP from the email and the verificationUUID from the previous response.

Let’s fill in our verify function with that in mind:

const verify = async () => {
  const options = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      verificationToken: OTP,
      verificationUUID: UUID,
    }),
  };

  fetch(
    `https://app.dynamicauth.com/api/v0/sdk/${DYNAMIC_ENVIRONMENT_ID}/emailVerifications/signIn`,
    options
  )
    .then((response) => response.json())
    .then((response) => {
      setVerifying(false);
      setJWT(response.jwt);
    })
    .catch((err) => console.error(err));
};

Get the JWT

At this point, you’ll have a JWT returned from the verify call and saved in state as the jwt variable. This JWT will be tied to a session in Dynamic, and we return details of the user from that JWT.

Learn more about the JWT object here.

Summary

That’s it! You now have a completely headless sign-in with email, using Dynamic OTP.