Create Next.js Application with passwordless authentication by using Magic

Magic is a simply Authentication Service and SDK. We can easy to create applications with passwordless / WebAu […]

広告ここから
広告ここまで

目次

    Magic is a simply Authentication Service and SDK. We can easy to create applications with passwordless / WebAuthn and Social Login.

    https://magic.link/

    Today, I’ve tried to create a new Next.js application and integrated it with Magic.

    Step1: Create a new Magic account

    We can start the service as free. https://dashboard.magic.link/signup is a Sign up page URL.

    After put our own email, we must not close or back from the page.

    We’ll get a confirm email from Magic, so we need to confirm it.

    Then, we can sign in to the dashboard.

    Step2: Get a API keys

    By default, we have an example application named First App. So let’s click the Get Started button.

    We can check the application’s publishable key and secret key.

    And if you want to clear these API Keys, we can regenerate it in the API Keys tab.

    Step3: Create a new Next.js application

    Next, we’ll create a new React application.

    I love to create Next.js applications using TypeScript. So I always use my own starter-template for Next.js.

    $ npx create-next-app magic-example  --example "https://github.com/wpkyoto/nextjs-starter-typescript/tree/main"
    $ cd magic-example

    And install the magic-sdk for frontend.

    $ yarn add  magic-sdk

    Then, we can setup the SDK like the following code.

    const client = new Magic('pk_test_xxxxx')

    If you want to use the client in several places, I recommend using useContext.

    const MagicContext = createContext<{
      magicClient?: Magic;
    }>({})
    
    const MagicProvider: FC<PropsWithChildren<{
      publishableAPIKey: string;
    }>> = ({publishableAPIKey, children}) => {
      const magic = useMemo(() => {
        if (typeof window === 'undefined') return;
        return new Magic(publishableAPIKey)
      }, [publishableAPIKey])
      return (
        <MagicContext.Provider value={{
          magicClient: magic,
        }}>
          {children}
        </MagicContext.Provider>
      )
    }
    
    const useMagic = () => useContext(MagicContext)

    tips: the Magic class using window property

    If you using any SSR enabled framework(Next.js / Gatsby / etc…), we should handle the window property before initialize the Magic class. Because the class may using the property, so when we use it in Node.js, we’ll get a ReferenceError: window is not defined error.

    We must check is the window not undefined.

    Step4: Check the login status

    We can check the user’s login status by using Magic.user.isLoggedIn.

      const {magicClient} = useMagic()
      const [isLogin, setLoginStatus] = useState(false)
      useEffect(() => {
        if (!magicClient) return;
        (async() => {
          const result = await magicClient.user.isLoggedIn()
          setLoginStatus(result)
        })()
      }, [magicClient, setLoginStatus])

    In this example, we can dispatch the following cases.

    • If the magicClient is undefined, this page will be loading.
    • If the magicClient is not undefined, and the isLogin is false, the user does not logged-in.
    • If the magicClient is not undefined, and the isLogin is true, the user does logged-in.

    So we can change the React component by these properties.

    Step5: Login / Sign-up by Email

    Finally, we can create a Login and Sign-up form. The Login and Sign up action can call from the same function.

    const useLoginByMagic = () => {
      const [errorMessage, setErrorMessage] = useState<string>(undefined)
      const [email, setEmail] = useState('')
      const [token, setToken] = useState<string>(undefined)
      const {magicClient} = useMagic()
      const handleLogin = useCallback(async() => {
        if (!magicClient) throw new Error('We have to initilize the magic client before use the hook. Or the Client can not use in Server Side process.')
        try {
          if (!email) throw new Error('Email is required')
          setErrorMessage(undefined)
          const magicAuthToken = await magicClient.auth.loginWithMagicLink({
            email
          })
          setToken(magicAuthToken)
        } catch (e) {
          console.error(e)
          setErrorMessage(e.message)
        }
      }, [email, magicClient, setToken, setErrorMessage])
      return {
        email,
        setEmail,
        token,
        errorMessage,
        handleLogin,
      }
    }

    This code is example React hook to handle the login / sign up process.

    We can update the user’s email by setEmail. And when calling the handleLogin function, Magic will be login or create a new user by the provided email address. We can watch the token and the errorMessage properties to check the login process result.

    If token is not undefined, the login process will be completed. And if the errorMessage is not undefined, the process may be failed by any reason.

    Conclusion: Simple and useful, but not cheap

    Magic is super simply authentication SaaS. We can easy to add the authentication feature into our own application.

    But, the free plan can create only 100 active users. If you have more users, we need to pay 35 USD per month or more. It’s a little bit expensive than Auth0 / AWS Cognito User Pools or Firebase.
    So I think it’s good for the paid application or closed application.

    If you feel expensive the prices, I recommend using Auth0 and create a passwordless / WebAuthn / Social Login feature by yourself.

    広告ここから
    広告ここまで

    Random posts

    Home
    Search
    Bookmark