Custom Signup

You can customize the user signup form with more fields in addition to email and password when using Lock or the Auth0 API.

There are many factors to consider before you choose Lock vs. Custom UI. For example, using Lock, you can redirect to another page to capture data or use progressive profiling. When using the Auth0 API, you can capture custom fields and store them in a database. There are certain limitations to the customization that should be considered when choosing the method that best suits your purpose. Some typical customizations include adding a username and verifying password strength.

Universal Login

Auth0 offers a Universal Login option that you can use instead of designing your own custom signup page. If you want to offer signup and login options, and you only need to customize the application name, logo and background color, then Universal Login via an Auth0 login page might be an easier option to implement.

Using Lock

Lock supports custom fields signup.

custom signup fields

Lock's additionalSignUpFields option will only work with database signups. For signups using social identity providers, collecting these fields in the same manner is not possible with Lock, but there are two other options to allow social IDP signups with Lock while still collecting additional custom fields.

Redirect to another page

One way to use social provider signups with Lock and collect custom fields is to use redirect rules to redirect the user to another page where you ask for extra information, and then redirect back to finish the authentication transaction.

Progressive profiling

Another way to collect custom field data when signing users up with social providers is via progressive profiling. Progressive profiling is a way by which you can slowly build up user profiles over time. You collect the bare minimum details upon signup, but when a user later interacts with your app, you collect a small amount of data (perhaps one question) each time until their profile is complete. This allows for collecting the desired information, but with less friction at signup, since the goal of using a social IDP for signup is, at least in part, making it more effortless and streamlined for the user.

For further reference, here is our documentation on progressive profiling as well as an Auth0 blog post on progressive profiling.

Using the API

1. Create a signup form to capture custom fields

<form id="signup">
  <fieldset>
    <legend>Sign up</legend>
    <p>
      <input type="email" id="signup-email" placeholder="Email" required/>
    </p>
    <p>
      <input type="password" id="signup-password" placeholder="Password"
             required/>
    </p>
    <p>
      <input type="text" id="name" placeholder="Full name" required/>
    </p>
    <p>
      <input type="text" id="color" placeholder="Favorite color"/>
    </p>
    <input type="submit" value="Sign up"/>
  </fieldset>
</form>

The name and color are custom fields.

There is currently no way to validate user-supplied custom fields when signing up. Validation must be done from an Auth0 Rule at login, or with custom, server-side logic in your application.

2. Send the form data

Send a POST request to the /dbconnections/signup endpoint in Auth0.

You will need to send:

  • Your application's client_id
  • The email and password of the user being signed up
  • The name of the database connection to store your user's data
  • Any custom fields as part of user_metadata

curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/dbconnections/signup' \
  --header 'content-type: application/json' \
  --data '{"client_id": "YOUR_CLIENT_ID","email": "$('\''#signup-email'\'').val()","password": "$('\''#signup-password'\'').val()","connection": "YOUR_CONNECTION_NAME","user_metadata": {"name": "john","color": "red"}}'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/dbconnections/signup");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{\"client_id\": \"YOUR_CLIENT_ID\",\"email\": \"$('#signup-email').val()\",\"password\": \"$('#signup-password').val()\",\"connection\": \"YOUR_CONNECTION_NAME\",\"user_metadata\": {\"name\": \"john\",\"color\": \"red\"}}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://YOUR_AUTH0_DOMAIN/dbconnections/signup"

	payload := strings.NewReader("{\"client_id\": \"YOUR_CLIENT_ID\",\"email\": \"$('#signup-email').val()\",\"password\": \"$('#signup-password').val()\",\"connection\": \"YOUR_CONNECTION_NAME\",\"user_metadata\": {\"name\": \"john\",\"color\": \"red\"}}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("content-type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://YOUR_AUTH0_DOMAIN/dbconnections/signup")
  .header("content-type", "application/json")
  .body("{\"client_id\": \"YOUR_CLIENT_ID\",\"email\": \"$('#signup-email').val()\",\"password\": \"$('#signup-password').val()\",\"connection\": \"YOUR_CONNECTION_NAME\",\"user_metadata\": {\"name\": \"john\",\"color\": \"red\"}}")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/dbconnections/signup",
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "processData": false,
  "data": "{\"client_id\": \"YOUR_CLIENT_ID\",\"email\": \"$('#signup-email').val()\",\"password\": \"$('#signup-password').val()\",\"connection\": \"YOUR_CONNECTION_NAME\",\"user_metadata\": {\"name\": \"john\",\"color\": \"red\"}}"
}

$.ajax(settings).done(function (response) {
  console.log(response);
});
var request = require("request");

var options = { method: 'POST',
  url: 'https://YOUR_AUTH0_DOMAIN/dbconnections/signup',
  headers: { 'content-type': 'application/json' },
  body: 
   { client_id: 'YOUR_CLIENT_ID',
     email: '$(\'#signup-email\').val()',
     password: '$(\'#signup-password\').val()',
     connection: 'YOUR_CONNECTION_NAME',
     user_metadata: { name: 'john', color: 'red' } },
  json: true };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"application/json" };
NSDictionary *parameters = @{ @"client_id": @"YOUR_CLIENT_ID",
                              @"email": @"$('#signup-email').val()",
                              @"password": @"$('#signup-password').val()",
                              @"connection": @"YOUR_CONNECTION_NAME",
                              @"user_metadata": @{ @"name": @"john", @"color": @"red" } };

NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/dbconnections/signup"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://YOUR_AUTH0_DOMAIN/dbconnections/signup",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"client_id\": \"YOUR_CLIENT_ID\",\"email\": \"$('#signup-email').val()\",\"password\": \"$('#signup-password').val()\",\"connection\": \"YOUR_CONNECTION_NAME\",\"user_metadata\": {\"name\": \"john\",\"color\": \"red\"}}",
  CURLOPT_HTTPHEADER => array(
    "content-type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
import http.client

conn = http.client.HTTPSConnection("")

payload = "{\"client_id\": \"YOUR_CLIENT_ID\",\"email\": \"$('#signup-email').val()\",\"password\": \"$('#signup-password').val()\",\"connection\": \"YOUR_CONNECTION_NAME\",\"user_metadata\": {\"name\": \"john\",\"color\": \"red\"}}"

headers = { 'content-type': "application/json" }

conn.request("POST", "/YOUR_AUTH0_DOMAIN/dbconnections/signup", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://YOUR_AUTH0_DOMAIN/dbconnections/signup")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/json'
request.body = "{\"client_id\": \"YOUR_CLIENT_ID\",\"email\": \"$('#signup-email').val()\",\"password\": \"$('#signup-password').val()\",\"connection\": \"YOUR_CONNECTION_NAME\",\"user_metadata\": {\"name\": \"john\",\"color\": \"red\"}}"

response = http.request(request)
puts response.read_body
import Foundation

let headers = ["content-type": "application/json"]
let parameters = [
  "client_id": "YOUR_CLIENT_ID",
  "email": "$('#signup-email').val()",
  "password": "$('#signup-password').val()",
  "connection": "YOUR_CONNECTION_NAME",
  "user_metadata": [
    "name": "john",
    "color": "red"
  ]
]

let postData = NSJSONSerialization.dataWithJSONObject(parameters, options: nil, error: nil)

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/dbconnections/signup")!,
                                        cachePolicy: .UseProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.HTTPMethod = "POST"
request.allHTTPHeaderFields = headers
request.HTTPBody = postData

let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    println(error)
  } else {
    let httpResponse = response as? NSHTTPURLResponse
    println(httpResponse)
  }
})

dataTask.resume()

Custom fields limitations

When your users sign up, the custom fields are sent as part of user_metadata. The limitations of this field are:

  • user_metadata must contain no more than 10 fields
  • user_metadata.field must be a string
  • user_metadata.field.value.length must be fewer than 500 characters
  • user_metadata.field.length must be fewer than 100 characters
  • The current size limit for user_metadata is 16 MB

Redirect mode

After a successful login, Auth0 will redirect the user to your configured callback URL with a JWT (id_token) in the query string.

To learn more about the differences between popup and redirect modes, please refer to this document.

window.auth0 = new Auth0({
  domain: 'YOUR_AUTH0_DOMAIN',
  clientID: 'YOUR_CLIENT_ID',
  // Callback made to your server's callback endpoint
  callbackURL: 'https://YOUR_APP/callback',
});

Your server will then need to call APIv2 to add the necessary custom fields to the user's profile.

Add username to the signup form

One common signup customization is to add a username to the signup.

To enable this feature, turn on the Requires Username setting on the Connections > Database section of the dashboard under the Settings tab for the connection you wish to edit.

Capture the username field in your custom form, and add the username to your request body.

<form id="signup">
  <fieldset>
    <legend>Sign up</legend>
    <p>
      <input type="email" id="signup-email" placeholder="Email" required/>
    </p>
    <p>
      <input type="password" id="signup-password" placeholder="Password"
             required/>
    </p>
    <p>
      <input type="text" id="username" placeholder="username" required/>
    </p>
    <input type="submit" value="Sign up"/>
  </fieldset>
</form>
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/dbconnections/signup",
  "method": "POST",
  "headers": {
    "content-type": "application/x-www-form-urlencoded"
  },
  "data": {
    "client_id": "YOUR_CLIENT_ID",
    "email": $('#email').val(),
    "password": $('#password').val(),
    "connection": "Username-Password-Authentication",
    "username": $('#username').val()
  }
}

$.ajax(settings).done(function (response) {
  console.log(response);
});

Optional: Verifying password strength

Password policies for database connections can be configured in the dashboard. For more information, see: Password Strength in Auth0 Database Connections.

If required for implementation of custom signup forms, the configured password policies, along with other connection information, can be retrieved from the Management v2 API. The result can be parsed client-side, and will contain information about the current password policy (or policies) configured in the dashboard for that connection.