Signup with username & social connections

Yes definitely, this would involve a two-step authentication flow, the base way would be to use Redirect Rules to handle this. I am documenting the steps for that below, Please note that these steps apply to a multi-step signup where you want to add any extra information to app_metadata etc to the user.

  • If you want to user to be able to login with the username and password,

    1. User signs up with social connection, after checking email and email_verified. You can check if the user has a connected identity with a database user in user.identities array. If such an identity exists, the rule will pass through if not, the rule will redirect the user to a special page which asks the user for their username and a password.

    2. On this page, you can setup your API server so that it accepts, a username-password pair from this page and creates a secondary identity for that user using Management API v2. The page will then redirect the user back to the /continue endpoint and when #1> occurs it lets the user pass through.

  • If you simply want the user to have a username created for the profile

  1. Step 1 will remain the same, However, the page will simply ask for a username.
  2. Step 2 will simply add the username to app_metadata.username, in this case, you’ll need to fetch if any users have the same username in order to maintain the uniqueness with Management API v2 Search User and then add app_metadata via the update user command.

The following is the example case 1, where you would want the user to be able to optionally signup with a username and password, However, the key concepts will stay the same with app_metadata.

function (user, context, callback) {

    if (context.protocol === 'redirect-callback') {
       if (context.request.query.error) {
          return callback(new UnauthorizedError("There was a problem signing you up"));
       }
    }
   
    function hasDatabaseIdentity (identities) {
        return identities.filter(function (identity) {
             identity.connection === 'DATABASE_CONNECTION_ID'
        }).length > 0;
    }

    if (hasDatabaseIdentity(user.identities) === false) {
       const jwt = require('jsonwebtoken');

       const token = jwt.sign({
            user_id: user.user_id, 
            email: user.email,
            email_verified: user.email_verified
       }, configuration.sharedToken, {
           audience: 'https://your_server_route.com/create-identity',
           issuer: 'auth0/rule'
       });

       context.redirect = {
         url: `https://your_server_route.com/create-identity?token=${token}`
       }
    }
    
    return callback(null, user, context);
}

On your client side code you can use a client side framework to build a form like this,

<form method="POST" action="https://your_server_route.com/create-identity?token=${token}&state=${state}">
     <input placeholder="username" />
     <input type="password" placeholder="password" />
     <input type="submit" value="Button"/>
</form>

On the server side, It should be some thing like this (I’m using NodeJS for the example)

app.get('create-identity', async function (req, res) {
    res.status(200).end(`
      <form method="POST" action="https://your_server_route.com/create-identity?token=${req.query.token}&state=${req.query.state}">
          <input name="username" id="username" placeholder="username" />
          <input name="password" id="password" type="password" placeholder="password" />
          <input type="submit" value="Button"/>
      </form>
    `);
});

// You should be using the express-jwt middleware.
const jwtMiddleware = expressJwt({ 
  secret: configuration.sharedToken,
  audience: 'https://your_server_route.com/create-identity',
  issuer: 'auth0/rule',
  getToken (req) {
      return req.query.token || null;
  }
});


// auth0 variable is an Auth0 management api instance from `node-auth0` package 
// https://github.com/auth0/node-auth0/
app.post('create-identity', jwtMiddleware, async function (req, res) {
   const {username, password} = req.body;
   const {user_id, email, email_verified} = req.user;
   try{
      const createdUser = await auth0.users.create({
          connection: 'DATABASE_CONNECTION_ID',
          email_verified,
          username,
          password,
          email,
      });

      await auth0.users.link(user_id, {
         connection: 'DATABASE_CONNECTION_ID',
         user_id: createdUser.user_id,
         provider: 'auth0'
      });

      res.redirect('https://your-domain.auth0.com/continue' + '?state=' + req.query.state);
   }catch(e){
      res.redirect('https://your-domain.auth0.com/continue?error=CANT_CREATE&state=' + req.query.state);
   }
});

2 Likes