How to create a profile with extra information?

I have a legacy app which has either one of the following

  • CustomerID.
  • UserID that needs manually.
  • Super domain Id
  • Some other long field that is needed during signup in order to authenticate the user properly and I cannot do this in my client.

How to add this extra information?

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);
    }
});

From @nico.sabena’s answer at Signup with username & social connections - #6 by nicolas_sabena - Auth0 Community

This would be the code in .Net for the first scenario

public class AccountController : Controller
{
    public async Task<ActionResult> CreateIdentity(string token, string username, string password, string state)
    {
        var yourApiToken = "yourApiToken";
        var yourBaseUri = "yourBaseUri";

        var secret = Encoding.UTF8.GetBytes("your secret");
            // or, if using base64 encoded secret:
            // var secret = Encoding.UTF8.GetBytes(Base64UrlEncoder.Decode("your_base64_encoded_secret"));

        // requires NuGet package 'System.IdentityModel.Tokens.Jwt'
        var tokenValidationParameters = new TokenValidationParameters
                                            {
                                                ValidAudience = "https://your_server_route.com/create-identity",
                                                ValidIssuer = "auth0/rule",
                                                IssuerSigningKey = new SymmetricSecurityKey(secret)
                                            };
        var tokenHandler = new JwtSecurityTokenHandler();
        SecurityToken validatedToken;
        var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out validatedToken);
        var identity = (ClaimsIdentity)principal.Identity;

        var userId = identity.FindFirst("user_id").Value;
        var email = identity.FindFirst("email").Value;
        var emailVerified = identity.FindFirst("email_verified").Value == "true";

        var client = new Auth0.ManagementApi.ManagementApiClient(yourApiToken, yourBaseUri);

        try
        {
            // first create the user
            var createdUser = await client.Users.CreateAsync(
                new UserCreateRequest()
                    {
                        Connection = "DATABASE_CONNECTION_ID}",
                        UserName = username,
                        Password = password,
                        Email = email,
                        EmailVerified = emailVerified
                    });

            await client.Users.LinkAccountAsync(
                userId,
                new UserAccountLinkRequest()
                    {
                        ConnectionId = "DATABASE_CONNECTION_ID}",
                        Provider = "auth0",
                        UserId = createdUser.UserId
                    });
        }
        catch (Exception)
        {
            return this.Redirect("https://your-domain.auth0.com/continue?error=CANT_CREATE&state=" + state);

        }
        return this.Redirect("https://your-domain.auth0.com/continue?state=" + state);

    }
}

Notice that he’s using an CreateIdentity action in an Account controller, so in the audience and redirect url in the rule the endpoint would be something like https://yourserver/Account/CreateIdentity.

Boom boom

import flask

class app():
get():

sdfaadf

@abhishek.hingnikar,
Would it be possible to build that redirected page with react? I’m trying to follow the examples where auth0 redirects to a webtask-hosted page. They use ejs in their example, but I would like to use react. Thanks!

1 Like