SSO Integration with ATS Anywhere

About SSO

Single Sign On, also known as SSO, is a means of authentication and authorization of a user to access a system based on previous authentication with another trusted system.

Many clients with multiple HR systems to manage find SSO to enable cleaner, faster workflows for their Hiring Managers and deliver a higher quality end user experience.

Prerequisites

In order to build an SSO integration with our ATS, you will need a shared secret which is used for SSO authentication purposes. To speak with someone about getting this feature set up, please reach out to [email protected]

SSO Technical Implementation

Once SSO is enabled, users will need to access the ATS through a URL in the following structure: https://login.applicant-tracking.com/sso/v2?name=John&[email protected]&company_number=123&company_name=WidgetCo&timestamp=XXXXXX&signature=asdfghjkl12345

You must use your custom ATS domain in place of applicant-tracking.com in order for your specific sso secret to be used.

The supported parameters in that URL are as follows:

  • name: The full name of the user
  • email: The user's email address
  • user_external_id (optional) - A unique identifier for this use. If not provided, email will be used
  • company_number - The unique alphanumeric identifier for the company accessing the ATS. This maps to the company's external_id.
  • company_name - The name of the company accessing the ATS. This is only used for initial account provisioning/
  • admin_level (optional) - The initial admin level for the user. Valid values can be found in our User's API section
    & timestamp - time in ISO8601 format
  • signature - SHA256 hash of user_external_id+email+company_number+timestamp+secret+admin_level. If you do not provide the optional parameters, they should be excluded from the signature.

If the company does not yet exist in the ATS, a new company account will be provisioned and the user will be set up as the AccountOwner with maximum permissions.

If the company already exists in the ATS, but the user does not, then a new user account will be created on that account with minimum permissions.

Sample Code

require 'date'
require 'digest'
require 'uri'

# required params:
#  name
#  email
#  company_number
#  company_name
# optional params:
#  user_external_id
#  admin_level
def sso_url(params)
  params[:timestamp] = DateTime.now.iso8601
  params[:signature] = generate_signature(params)

  URI::HTTPS.build(
    host: "login.your-ats-domain.com",
    path: "/sso/v2",
    query: URI.encode_www_form(params)
  ).to_s
end

def generate_signature(params)
  digest = Digest::SHA2.new(256)

  # Optional, add to signature if present
  digest << params[:user_external_id] if params[:user_external_id]

  digest << params[:email]
  digest << params[:company_number]
  digest << params[:timestamp]
  digest << "your_secret_here"

  # Optional, add to signature if present
  digest << params[:admin_level] if params[:admin_level]

  digest.hexdigest
end

puts sso_url(
  name: "Bob Jones",
  email: "[email protected]",
  company_name: "Widgets R Us",
  company_number: "c7",
  admin_level: "Admin",
  user_external_id: "u22"
)
const sha256 = require("crypto-js/sha256");

// required params:
//  name
//  email
//  company_number
//  company_name
// optional params:
//  user_external_id
//  admin_level
const buildUrl = (params) => {
  const url = new URL("https://login.your-ats-domain.com/sso/v2");
  const urlParams = new URLSearchParams();
  for (const [key, value] of Object.entries(params)) {
    urlParams.append(key, value);
  }

  urlParams.append("timestamp", new Date().toISOString());

  let digest = "";

  if (params.user_external_id) {
    // Optional, add to signature if present
    digest += params.user_external_id;
  }

  digest += params.email;
  digest += params.company_number;
  digest += params.timestamp;

  digest += "your sso secret";

  if (params.adminLevel) {
    // Optional, add to signature if present
    digest += params.admin_level;
  }

  const sig = sha256(digest);
  urlParams.append("signature", sig);

  url.search = urlParams;
  return url.toString();
};

const url = buildUrl({
  name: "Bob Jones",
  email: "[email protected]",
  company_name: "Widgets R Us",
  company_number: "c7",
  admin_level: "Admin",
  user_external_id: "u22",
});
console.log(url);
/*
  * Required parameters:
  *   name
  *   email
  *   company_number
  *   company_name
  * Optional parameters:
  *   user_external_id
  *   admin_level
  */
static string BuildSsoUrl(Dictionary<string, string> prams)
{
    prams["timestamp"] = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
    prams["signature"] = GenerateSignature(prams);

    var url = new UriBuilder("https://login.your-ats-domain.com/sso/v2");
    url.Query = String.Join("&", prams.Select(p => p.Key + "=" + HttpUtility.UrlEncode(p.Value)));

    return url.ToString();
}

static string GenerateSignature(Dictionary<string, string> prams)
{
    var sha256 = System.Security.Cryptography.SHA256.Create();
    var signature = new StringBuilder();

    if (prams.ContainsKey("user_external_id"))
    {
        // Optional, add to signature if present
        signature.Append(prams["user_external_id"]);
    }

    signature.Append(prams["email"]);
    signature.Append(prams["company_number"]);
    signature.Append(prams["timestamp"]);
    signature.Append("your sso secret");

    if (prams.ContainsKey("admin_level"))
    {
        // Optional, add to signature if present
        signature.Append(prams["admin_level"]);
    }

    var signatureBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(signature.ToString()));

    return String.Join("",signatureBytes.Select(b => b.ToString("x2")));
}
static void Main(string[] args)
{
    Console.WriteLine(
        BuildSsoUrl(new Dictionary<string, string> {
            { "name", "Bob Jones" },
            { "email", "[email protected]" },
            { "company_name", "Widgets R Us" },
            { "company_number", "c7" },
            { "admin_level", "Admin" },
            { "user_external_id", "u22" }
        })
    );
}

Hard SSO Cutover

By default, the ATS will still support traditional user login pages in addition to SSO access. Upon request, the system can be configured to only allows SSO access. Please specify this request to [email protected] once your SSO configuration is enabled.

SAML v2.0 Support

ATS Anywhere also supports SSO via the SAML 2.0 standard. If you would prefer to integrate with this standard, please let us know at [email protected]