Passwordless flow using auth0-js does not work! Documentation is wrong too

Please include the following information in your post:

SDK: auth0-js
SDK Version: 9.16.0
Platform Version: Node 14.15.5
Application Type: Regular Application (NextJS)

Hello,

I’m trying to implement passwordless flow using the auth0-js SDK. I don’t want to use the Universal Login because the customisation offered are not sufficient enough.

My application is a “Regular Web Application” (NextJS). I’m not using nextjs-auth0 because that again wants me to use Universal Login which isn’t what we want.

We’ve also enabled the Customize Login Page in Auth0 Dashboard → Universal Login → Login → Customize Login Page. As well as enabled the Passwordless OTP grant for target application.

Following the Auth0 SDK here (Auth0.js v9 Reference) I’ve done the following at high level:

  1. Initiate the Passwordless flow at the backend. I have to do the passwordless start at server side since client secret is now required (see this comment from auth0 dev: Passwordless connection not working for tenants created after Jan 2, 2020 - #6 by thameera)

    // pages/api/passwordless.js
    export default async (req, res) => {
    
     await axios.post(`https://${process.env.AUTH0_DOMAIN}.au.auth0.com/passwordless/start`, {
         client_id: process.env.AUTH0_CLIENT_ID,
         client_secret: process.env.AUTH0_CLIENT_SECRET,
         connection: 'email',
         email: 'SOME USER EMAIL',
         send: 'link',
         authParams: {
             // any authentication parameters that you would like to add
             redirectUri: 'http://localhost:3000/auth/callback',
             responseType: 'token',
         },
     });
    
     res.status(200);
    

};

  1. user clicks the email link received in their inbox

  2. Auth0 redirects to our callback pages (http://localhost:3000/auth/callback). The url that /callback has is something like (http://localhost:3000/callback#access_token=7Cl7_LLrWIpuEuuKSghAPRp00000000&scope=openid&expires_in=7200&token_type=Bearer)

  3. we handle the callback fragments using:

     import React, { Component, useEffect } from 'react';
     import { useRouter } from 'next/router';
     import auth0 from 'auth0-js';
    
     const auth0 = new auth0.WebAuth({
         domain: 'OUR_AUTH0_DOMAIN.au.auth0.com',
         audience: 'https://OUR_AUTH0_DOMAIN.au.auth0.com/api/v2/',
         clientID: 'OUR ACTUAL CLIENT ID',
         redirectUri: 'http://localhost:3000/auth/callback',
         responseType: 'token',
         scope: 'openid email offline_access',
     });
    
     // pages/callback
     const Callback = () => {
         const router = useRouter();
    
         const handleAuthentication = () => {
             return new Promise((resolve, reject) => {
    
             auth0.parseHash((err, authResult) => {
                 if (authResult && authResult.accessToken && authResult.idToken) {
                 this.auth0.client.userInfo(authResult.accessToken, (err, user) => {
                     if (err) {
                     reject(err);
                     }
    
                     resolve(user);
                 });
                 } else if (err) {
                 reject(err);
                 window.location.replace('/');
                 }
             });
             });
         };
    
         useEffect(() => {
             handleAuthentication()
             .then((res) => {
                 router.push('/protected_page');
             })
             .catch((err) => {
                 router.push('/');
             });
         }, []);
    
         return <div />;
     };
    
     export default Callback;
    
  4. The auth0.parseHash at this point gives an error saying

    {error: "invalid_token", errorDescription: "`state` does not match."}
    

At this point i don’t know what i’m doing wrong :grimacing: Is there a working example somewhere of how we’re meant to implement passwordless flow using auth0-js and regular application without using Universal Login? Would highly appreciate an example.

I also get this error ({error: “consent_required”, error_description: “Consent required”}) but i understand this is a localhost thing so i’m not too concerned about this for now.

To Auth0:

  • Documentation of auth0-js isn’t updated anymore? If i just use the code sample from the documentation, that simply does not work.

Anyone knows what i’m doing wrong?

Thanks

Based on the conversation here (`state` does not match - #2 by nicolas_sabena), i can see why i am getting the state does not match error.

Issue is, Auth0 requires the passwordless flow to be started on server (see Passwordless connection not working for tenants created after Jan 2, 2020 - #6 by thameera) otherwise you could get “Client authentication is required”.

In other words:

  • if i start the passwordflow on server side, i get ``state does not match because obviously client doesn’t have the state.
  • i cannot start the passwordless flow on client side because call to /passwordless/start requires client secret along side client id. If i don’t supply the client secret and try to start the passwordless flow on client side, i get Client authentication is required.

Would appreciate any help i can in solving this @thameera @andres.aguiar @konrad.sopala @nicolas_sabena

Hey @john18 :wave: I think there’s a bit of confusion here. The client secret is required only if it is a confidential app (i.e. a “regular web application” in Auth0 application terminology), as mentioned in the response you linked from the other thread.

If you are using frontend flows, you can still continue calling /passwordless/start without a client secret. For this, you must make sure that the application is marked as a Single Page Application.

Afterwards, you can use Auth0.js’s passwordless methods: Auth0.js v9 Reference

2 Likes

Thanks for replying @thameera. I’m building on top of NextJS and as per the guide that comes for Auth0 when you create your application, it wanted me to create “Regular Web App” for nextjs. So is this correct:

  • Regular web app: where you need the server to know about the user’s auth state, which is managed by nextjs-auth0

  • SPA where Auth0.js does it’s thing and for all the API calls one must pass the Bearer token and have the APIs validate the token as needed?

Roughly correct?

That’s right! Next.js can be used both as a SPA and an RWA.
As a SPA - you would start the login at the frontend and get the tokens in the frontend.
As an RWA - both of those will happen at the backend. The callback URL would be a backend endpoint (eg: https://example.com/api/callback)

Generally RWAs are preferred, and Auth0’s Next.js SDK uses that pattern as well: GitHub - auth0/nextjs-auth0: Next.js SDK for signing in with Auth0
The SDK uses Auth0’s universal login page.

Technically, you’ll be able to get passwordless working with a backend flow as well. You’ll need to set the responseType to code and make sure the callback URL is a backend endpoint. I’ll not go into detail here.

2 Likes

Thanks for helping on this one Thameera!

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.