DEV Community

Cover image for Authentication with magic link in React
Gogulaanand
Gogulaanand

Posted on

Authentication with magic link in React

Authenticating users via magic link is on the rise recently (for a good reason). Magic link is the way of sending users a unique link to their mail, using which they can signup / login. It removes the need for username, password, activation email, forgot password scenarios etc.

magic.link offers an npm package which we can plug into our app and have an auth system setup in few minutes.

Lets begin 🚀

Installation:

npm i magic-sdk
Enter fullscreen mode Exit fullscreen mode

Import and initialise magic


import { Magic } from "magic-sdk";

const [user, setUser] = useState(null);

useEffect(() => {
    magic = new Magic(process.env.NEXT_PUBLIC_MAGIC_API_KEY)
}, []);
Enter fullscreen mode Exit fullscreen mode

NEXT_PUBLIC_MAGIC_API_KEY is the api key provided by magic.link, stored in local environment.

User login

const loginUser = async (email) => {
    try {
      await magic.auth.loginWithMagicLink({ email });
      setUser(email);
      router.push("/");
    } catch (err) {
      setUser(null);
      throw new Error("Email login failed");
    }
  };
Enter fullscreen mode Exit fullscreen mode

To verify user session:

Once a user has clicked the magic link received in his mail and completed the authentication, magic would automatically store the user meta data in your site's localstorage/cookies. We simply need to use the inbuilt function to fetch the stored session token and user's data which is email here.

const checkUserLoggedIn = async () => {
  try {
    const isLoggedIn = await magic.user.isLoggedIn();
    if (isLoggedIn) {
      const { email } = await magic.user.getMetadata();
      setUser(email);
      getToken();
    }
  } catch (err) {
    throw new Error("User is not logged in");
  }
};

const getToken = async () => {
  try {
    return await magic.user.getIdToken();
  } catch (err) {
    throw new Error("Authenticate current session failed");
  }
};
Enter fullscreen mode Exit fullscreen mode

Invoke checkUserLoggedIn() inside useEffect hook.

User logout:

const logoutUser = async () => {
    try {
      await magic.user.logout();
      setUser(null);
      router.push("/");
    } catch (err) {
      throw new Error("User logout failed");
    }
  };
Enter fullscreen mode Exit fullscreen mode

Oauth login:

You can follow the quick setup guide for social login under your magic account. (Trust me, it is not a long guide. It just takes couple of minutes 😄) Once done, we can setup oauth login in our app.

Installation:

npm i @magic-ext/oauth
Enter fullscreen mode Exit fullscreen mode

A minor change to our magic initialisation to support oauth.

import { OAuthExtension } from "@magic-ext/oauth";

useEffect(() => {
    magic = new Magic(process.env.NEXT_PUBLIC_MAGIC_API_KEY, {
      extensions: [new OAuthExtension()],
    });
}, []);
Enter fullscreen mode Exit fullscreen mode
const oauthLogin = async (e) => {
    e.preventDefault();

    // Start the Google OAuth 2.0 flow!
    await magic.oauth.loginWithRedirect({
      provider: "google",
      redirectURI: `${window.location.origin}/oauth`,
    });
  };
Enter fullscreen mode Exit fullscreen mode

Invoke above method when the user clicks on the 'Sign in with Google' button. Here, i have provided redirectURI as /oauth. Once the google login is complete, magic will redirect to this endpoint of our website. We can have a success page under that endpoint or just redirect to hompage simply using / instead /oauth

Some additional logic to add to our useEffect hook:

useEffect(() => {
    magic = new Magic(process.env.NEXT_PUBLIC_MAGIC_API_KEY, {
      extensions: [new OAuthExtension()],
    });

    const render = async () => {
      if (window.location.pathname === "/oauth") {
        try {
          const result = await magic.oauth.getRedirectResult();
          const profile = JSON.stringify(result.oauth.userInfo, undefined, 2);
          if (profile.email) {
            setUser(profile.email);
            router.push("/");
          }
        } catch {
          window.location.href = window.location.origin;
          throw new Error("Oauth login failed");
        }
      }

      checkUserLoggedIn();
    };
    render();
  }, []);
Enter fullscreen mode Exit fullscreen mode

The only new thing here is the render() method inside useEffect. It checks if current url is /oauth, then fetches the user details obtained via oauth login. The profile varibable contains many details, but for simplicity, here we are using only the email.

And...
That's it. 🎉
We have an email and google login setup for our app/website.
Without the worries of the problems that passwords bring in. 😌

Credits: Cover Photo by Franck on Unsplash

📌 magic.link provides 10000 free logins currently which supports hobby/pet projects suffciently. If you are interested and want to checkout magic, signup here 😉

Discussion (0)