SSO Authentication

How It Works

First a user will sign into your external site. Once they have been authenticated, your application will construct a token (JWT) and redirect to the Deeper Signals SSO URL with this token as a query string parameter. Deeper Signals deconstructs this payload and either finds the user and signs them in, or if they don't already have an account on your Deeper Signals site, creates an account and signs them in.

The Deeper Signals SSO URL

The Deeper Signals SSO URL is the URL that you redirect to after a user has successfully authenticated in your system. It has the following structure:

  • The jwt parameter is the JWT payload that you construct and is REQUIRED.
  • The error_url is the url that you want the user to be redirected to in the case of an error. This is OPTIONAL.
  • If the error_url is not supplied, the user will be redirected to a generic Deeper Signals error page.
      https://app.deepersignals.com/sso/{JWT-TOKEN}

The JWT Payload

Your application must construct the JWT payload and sign it using your Deeper Signals API key. The key can be found under the API section of your Deeper Signals admin dashboard. If you don't see API options in your admin dashboard, request API permissions from your Deeper Signals account administrator. The best practice for security is to generate the JWT token on a server and then retrieve it from the client side, rather than exposing the JWT shared secret in the client-side JavaScript.

Note : Do not base 64 encode your API key when signing your JWT token. Our application expects the API key as-is when verifying your JWT token.

The JWT payload is typically constructed as a hash. The following attributes are supported:

{
				"iat": 1620212314,
				"exp": 1620215914,
				"client_id": "6hUsd268",
				"email": "user@deepersignals.com",
				"first_name": "deeper",
				"last_name": "Signals",
				"ds_id":1,
				"locale": "en",
				"identity": "USHdUHi6"
}

  • iat (required) - must be the number of seconds since UNIX epoch. This is essentially the time that the JWT payload was issued.
  • exp (requierd) - UNIX epoch timestamp modified to represent the expiery time NOTE: The maximum token validity period is 15 minutes but this parameter can be used to shorten that period
  • client_id(requierd) - when generating your api token you will be supplied with a corresponding client id which must be supplied in the JWT claims
  • email (required) - the email of the authenticated user. If ds_id is not supplied, email will be used as the unique identifier to find a user.
  • first_name (required)- the first name of the authenticated user.
  • last_name (required)- the last name of the authenticated user.
  • ds_id(optional) - the id of the user in the Deeper Signals system. You will get supplied with this paramter when a user gets created through our webhook or the callback url
  • locale(optional) - the two letter code of a users language. The default is eng and if the language provided is not supported the fallback will be English
  • identity - this is the playbook identity which should be used after the user is registered/logged in to assign the user assessments, associate him with groups and/or projects

There are various libraries for working with JWT. A list can be found here. We recommend using the HS256 algorithm.

One thing to be aware of is that the JWT payload is merely encoded and signed, not encrypted, so don’t put any sensitive data in the hash table. JWT works by serializing the JSON that is being transmitted to a string. It then base 64 encodes that string and then makes an HMAC of the base 64 string which depends on the shared secret. This produces a signature that the recipient side can use to validate the user.

API Authentication

How It Works

The api authentication works through the api token which is sent with every authenticated request in the X-TOKEN header.

The api token will be provided by Deeper Signals to you, and is state less. In addition when requesting an api token valid redirect domains need to be provided in order for the SSO error url functionality to work.

The Playbook

What it is?

The playbook is created via API and is used to define actions which should happen after a user is logged in or registered with an SSO link. Using the playbook you can define a couple of options like which assessments should be assigned to a user, which projects the user should join, which groups the user should be assigned.

This concept is used to minimize the number of API calls for creating a user. You create a playbook once and you use it multiple times. In that way you have no API calls when creating a user, you just use the identity of the playbook, sign the JWT token, redirect the user to our sso url and you are all set. The user is created and their assessments are assigned.

How it works

When a playbook gets created a unique identifier is created for the specific playbook. You can send that identifier as a part of the SSO JWT token payload under the identity key.

CreatePlaybook

curl -X POST -d '{
    "name":"TestPlaybook2",
    "assessments":[{"id":230}],
    "projects":[{"id":1}],
    "groups":[{"name":"TestGroup"}]
}' "https://api.deepersignals.com/api/external/playbook/create"
POST /api/external/playbook/create HTTP/1.1
Host: api.deepersignals.com

{
    "name":"TestPlaybook2",
    "assessments":[{"id":230}],
    "projects":[{"id":1}],
    "groups":[{"name":"TestGroup"}]
}
Status 200 OK
{
    "id": 3,
    "assessments": [
        {
            "id": 230,
            "form_id": "LDKXFvaWTq",
            "name": "Core Drivers Pro"
        }
    ],
    "groups": [
        {
            "id": 135,
            "name": "TestGroup"
        }
    ],
    "projects": [
        {
            "id": 1,
            "name": "TestProject"
        }
    ],
    "name": "TestPlaybook2",
    "identity": "60ae0168f2eb7",
    "account": {
        "id": 1,
        "name": "Deeper Signals",
        "index_name": "deepersignals"
    }
}

updatePlaybook

curl -X PUT -d '{
    "name":"TestPlaybook3",
    "assessments":[{"id":230}],
    "projects":[{"id":1}],
    "groups":[{"name":"TestGroup"}]
}' "https://api.deepersignals.com/api/external/playbook/{playbook_id}"
PUT /api/external/playbook/{playbook_id} HTTP/1.1
Host: api.deepersignals.com

{
    "name":"TestPlaybook3",
    "assessments":[{"id":230}],
    "projects":[{"id":1}],
    "groups":[{"name":"TestGroup"}]
}
Status 200 OK
{
    "id": 1,
    "assessments": [
        {
            "id": 230,
            "form_id": "LDKXFvaWTq",
            "name": "Core Drivers Pro"
        }
    ],
    "groups": [
        {
            "id": 135,
            "name": "TestGroup"
        }
    ],
    "projects": [
        {
            "id": 1,
            "name": "TestProject"
        }
    ],
    "name": "TestPlaybook3",
    "identity": "609bb25b0e9c9",
    "account": {
        "id": 1,
        "name": "Deeper Signals",
        "index_name": "deepersignals"
    }
}

removePlaybook

curl -X DELETE "https://api.deepersignals.com/api/external/playbook/{playbook_id}"
DELETE /api/external/playbook/{playbook_id} HTTP/1.1
Host: api.deepersignals.com
Status 204 No Content

getPlaybooks

curl -X GET "https://api.deepersignals.com/api/external/playbook"
GET /api/external/playbook HTTP/1.1
Host: api.deepersignals.com
Status 200 OK
[
    {
        "id": 2,
        "assessments": [
            {
                "id": 230,
                "form_id": "LDKXFvaWTq",
                "name": "test"
            }
        ],
        "groups": [],
        "projects": [
            {
                "id": 1,
                "name": "TestP"
            }
        ],
        "name": "TestPlaybook2",
        "identity": "609bb8de73a32",
        "account": {
            "id": 1,
            "name": "Deeper Signals",
            "index_name": "deepersignals"
        }
    },
    {
        "id": 3,
        "assessments": [
            {
                "id": 230,
                "form_id": "LDKXFvaWTq",
                "name": "test"
            }
        ],
        "groups": [
            {
                "id": 135,
                "name": "TestGroup"
            }
        ],
        "projects": [
            {
                "id": 1,
                "name": "TestP"
            }
        ],
        "name": "TestPlaybook3",
        "identity": "60ae0168f2eb7",
        "account": {
            "id": 1,
            "name": "Deeper Signals",
            "index_name": "deepersignals"
        }
    }
]

Projects

Projects are used so you can more easily manage the users of your assessment. If a user is part of a project their results aree conveniently grouped within the same project.

getProjects

curl -X GET "https://api.deepersignals.com/api/external/project"
GET /api/external/project HTTP/1.1
Host: api.deepersignals.com
Status 200 OK
[
    {
        "id": 1,
        "name": "TestProject"
    },
    {
        "id": 2,
        "name": "TestProject2"
    }
]

Assessments

GetAssessments

curl -X GET "https://api.deepersignals.com/api/external/assessments"
GET /api/external/assessments HTTP/1.1
Host: api.deepersignals.com
Status 200 OK
[
    {
        "assessment": {
            "id": 230,
            "form_id": "LDKXFvaWTq",
            "name": "test",
            "enabled": true,
            "library": {
                "id": 19,
                "quiz_key": "YExBLe3yfp",
                "data_quiz_key": "YExBLe3yfp",
                "name": "Core Drivers Leadership"
            },
            "pristine": true,
            "pristine_core": true,
            "created_at": "2021-02-12 19:32:11"
        },
        "comparable": true,
        "count": 8
    },
    {
        "assessment": {
            "id": 231,
            "form_id": "F8BY2caUww",
            "name": "Beliefs",
            "enabled": true,
            "library": {
                "id": 15,
                "quiz_key": "lOJSyg76eq",
                "data_quiz_key": "aYw9FadbGY",
                "name": "Beliefs"
            },
            "pristine": true,
            "pristine_core": true,
            "created_at": "2021-03-31 12:55:32"
        },
        "comparable": false,
        "count": 4
    }
]

User

getUserWithResults

curl -X GET "https://api.deepersignals.com/api/external/users/{user_id}/results"
GET /api/external/users/{user_id}/results HTTP/1.1
Host: api.deepersignals.com
Status 200 OK
{
    "user": {
        "user_id": 1,
        "first_name": "Deeper",
        "last_name": "Signals",
        "email": "user@deepersignals.com",
        "gender": "M",
        "company": "DeeperSignals",
        "groups": [
            "DeeperSignals"
        ],
        "projects": [],
        "status": "NORMAL",
        "locale": "it",
        "country": {
            "country_id": 3,
            "country": "USA"
        },
        "state": {
            "state_id": 45,
            "state": "Badakhshan"
        },
        "education": {
            "education_id": 1,
            "education": "High School"
        },
        "income": {
            "income_id": 1,
            "income": "Under $23,000"
        },
        "job_level": {
            "job_level_id": 1,
            "job_level": "Student"
        },
        "age": {
            "age_id": 1,
            "age": "Between 18 and 25"
        }
    },
    "userAssessments": {
        "LDKXFvaWTq": {
            "assessment": {
                "formId": "LDKXFvaWTq",
                "name": "Core Drivers Pro",
                "status": "completed",
                "retake": true
            },
            "scales": {
                "Openness": 54.6,
                "Openness//Expressive": 96,
                "Openness//Imaginative": 70.2,
                "Openness//Artistic": 22.9,
                "Openness//Inquisitive": 19.4,
                "Openness//Experimental": 10.9,
                "Stability": 55.5,
                "Stability//Reflective": 4,
                "Stability//Resilient": 69.4,
                "Stability//Composed": 22.9,
                "Stability//Inattentive": 16.2,
                "Stability//Calm": 60.6,
                "Stability//Anxious": 1,
                "Stability//Positive": 16.4,
                "Agreeableness": 68.9,
                "Agreeableness//Empathetic": 91.2,
                "Agreeableness//Helpful": 11.8,
                "Agreeableness//Trusting": 93.5,
                "Agreeableness//Cooperative": 13.5,
                "Agreeableness//Moral": 58.3,
                "Conscientiousness": 46.1,
                "Conscientiousness//Dutiful": 39.6,
                "Conscientiousness//Perfectionist": 56.2,
                "Conscientiousness//Self-disciplined": 14.1,
                "Conscientiousness//Organized": 47.4,
                "Conscientiousness//Cautious": 30.2,
                "Conscientiousness//Impulsive": 4,
                "Extraversion": 27.7,
                "Extraversion//Friendly": 28.9,
                "Extraversion//Sociable": 39.2,
                "Extraversion//Colorful": 41.5,
                "Extraversion//Thrill-seeking": 22.3,
                "Extraversion//Upbeat": 28.6,
                "Drive": 70,
                "Drive//Proactive": 76.9,
                "Drive//Goal-oriented": 58.9,
                "Drive//Confident": 72.4,
                "Drive//Competitive": 38.2,
                "Drive//Leading": 77,
                "Considerate": 68.9,
                "Candid": 31.099999999999994,
                "Disciplined": 46.1,
                "Flexible": 53.9,
                "Driven": 70,
                "Laid-back": 30,
                "Outgoing": 27.7,
                "Reserved": 72.3,
                "Curious": 54.6,
                "Pragmatic": 45.4,
                "Stable": 55.5,
                "Passionate": 44.5
            }
        },
        "F8BY2caUww": {
            "assessment": {
                "formId": "F8BY2caUww",
                "name": "Core Values",
                "status": "completed",
                "retake": true
            },
            "scales": {
                "Relatedness": 11.36,
                "Inquiry": 3.82,
                "Mastery": 31.78,
                "Novelty": 78.83,
                "Power": 54.04,
                "Virtue": 42.8
            }
        }
    }
}

getUserDetails

curl -X GET "https://api.deepersignals.com/api/external/users/{user_id}"
GET /api/external/users/{user_id} HTTP/1.1
Host: api.deepersignals.com 
Status 200 OK
{
    "id": 1,
    "email": "user@deepersignals.com",
    "roles": [
        "ROLE_USER"
    ],
    "first_name": "deeper",
    "last_name": "signals",
    "active": true,
    "created_at": "2019-01-10 11:02:55",
    "profile": {
        "id": 1,
        "company": "Deepersignals",
        "gender": "M",
        "age": {
            "id": 1,
            "name": "Between 18 and 25"
        },
        "country": {
            "id": 3,
            "name": "United States",
            "code": "US"
        },
        "state": {
            "id": 45,
            "name": "California"
        },
        "education": {
            "id": 1,
            "name": "High School"
        },
        "income": {
            "id": 1,
            "name": "Under $23,000"
        },
        "job_level": {
            "id": 1,
            "name": "Student"
        },
        "image_path": null
    },
    "account": {
        "id": 1,
        "name": "Deeper Signals",
        "index_name": "deepersignals",
        "whitelabel": true,
        "created_at": "2019-04-30 12:05:48",
        "updated_at": "2021-04-26 16:31:43"
    },
    "updated_at": "2021-04-30 16:22:02",
    "info": [],
    "status": "NORMAL",
    "emailVerified": true,
    "MFA": false,
    "last_login_at": "2021-04-21T08:44:58+02:00",
    "locale": "it",
    "groups": [
        "DeeperSignals"
    ]
}

deleteUser

curl -X DELETE "https://api.deepersignals.com/api/external/users/15764"
DELETE /api/external/users/15764 HTTP/1.1
Host:https://api.deepersignals.com 
Status 204 No Content

createUser

curl -X POST -d '{

                "first_name": "deeper",
                "last_name": "Signals",
                "locale": "en",
                "email":"deeperrr@signal.com",
                "groups": ["testG"]
}' "https://api.deepersignals.com/api/external/user"
POST /api/external/user HTTP/1.1
Host:

{

                "first_name": "deeper",
                "last_name": "Signals",
                "locale": "en",
                "email":"deeperrr@signal.com",
                "groups": ["testG"]
}
Status 200 OK
Content-Type application/json
{
    "id": 15768,
    "email": "deeperrr@signal.com",
    "roles": [
        "ROLE_USER"
    ],
    "first_name": "deeper",
    "last_name": "Signals",
    "active": true,
    "created_at": "2021-07-08 10:43:34",
    "profile": {
        "id": 15448,
        "company": "N/A",
        "gender": "N/A",
        "age": {
            "id": 7,
            "name": "N/A"
        },
        "ethnicity": null,
        "country": {
            "id": 235,
            "name": "N/A",
            "code": "N/A"
        },
        "state": {
            "id": 3923,
            "name": "N/A"
        },
        "education": {
            "id": 6,
            "name": "N/A"
        },
        "income": {
            "id": 5,
            "name": "N/A"
        },
        "job_level": {
            "id": 5,
            "name": "N/A"
        },
        "image_path": null
    },
    "account": {
        "id": 1,
        "name": "Deeper Signals",
        "index_name": "deepersignals",
        "whitelabel": true,
        "created_at": "2019-04-30 12:05:48",
        "updated_at": "2021-05-12 09:58:15"
    },
    "updated_at": "2021-07-08 10:43:34",
    "info": [],
    "status": "NORMAL",
    "emailVerified": false,
    "locale": "en"
}
Status 409 Conflict
Content-Type application/json
{
    "message": "User already exists.",
    "code": 409,
    "trans_code": "exception.user.alreadyExists",
    "data": null
}

getUserByEmail

curl -X GET "https://api.deepersignals.com/api/external/user/email/{email_address}"
GET /api/external/user/email/{email_address} HTTP/1.1
Host:

Status 200 OK
Content-Type application/json
{
    "id": 15768,
    "email": "deeperrr@signal.com",
    "roles": [
        "ROLE_USER"
    ],
    "first_name": "deeper",
    "last_name": "Signals",
    "active": true,
    "created_at": "2021-07-08 10:43:34",
    "profile": {
        "id": 15448,
        "company": "N/A",
        "gender": "N/A",
        "age": {
            "id": 7,
            "name": "N/A"
        },
        "ethnicity": null,
        "country": {
            "id": 235,
            "name": "N/A",
            "code": "N/A"
        },
        "state": {
            "id": 3923,
            "name": "N/A"
        },
        "education": {
            "id": 6,
            "name": "N/A"
        },
        "income": {
            "id": 5,
            "name": "N/A"
        },
        "job_level": {
            "id": 5,
            "name": "N/A"
        },
        "image_path": null
    },
    "account": {
        "id": 1,
        "name": "Deeper Signals",
        "index_name": "deepersignals",
        "whitelabel": true,
        "created_at": "2019-04-30 12:05:48",
        "updated_at": "2021-05-12 09:58:15"
    },
    "updated_at": "2021-07-08 10:43:34",
    "info": [],
    "status": "NORMAL",
    "emailVerified": false,
    "locale": "en"
}
Status 404 Not Found
Content-Type application/json
{
    "message": "User not found",
    "code": 404,
    "trans_code": "exception.user.notFound",
    "data": null

}

The webhook

The webhook is registerd in your account settings on the Deeper Signals App. From the webhook url you can get a few type of events which you can see listed in the table below with their json payloads. Webhook settings are not enabled by default. Contact your Deeper Signals administrator to have these settings enabled.


Status 200 OK
{
  "form_id": "MbzjlmiKPm",
  "name": "Core Drivers Leadership",
  "event": "AssessmentCreated"
}
Status 200 OK
{
  "form_id": "MbzjlmiKPm",
  "name": "Core Drivers Leadership",
  "event": "AssessmentDeleted"
}
}
Status 200 OK
Note Scales might be different on different kinds of assessments. This is an example for the Core Drivers Pro assessment.
{
  "id":1,
  "full_name": "John Doe",
  "email": "user@deepersignals.com",
  "groups": [],
  "company": "N\/A",
  "country": "N\/A",
  "state": "N\/A",
  "started_at": "2020-11-08T19:16:50+01:00",
  "finished_at": "2020-11-08T19:16:55+01:00",
  "scales": {
    "Openness": 40.8,
    "Openness\/\/Artistic": 94.7,
    "Openness\/\/Imaginative": 9,
    "Openness\/\/Expressive": 42,
    "Openness\/\/Inquisitive": 8.8,
    "Openness\/\/Experimental": 69.2,
    "Agreeableness": 26.6,
    "Agreeableness\/\/Trusting": 93.5,
    "Agreeableness\/\/Empathetic": 28.7,
    "Agreeableness\/\/Helpful": 11.8,
    "Agreeableness\/\/Cooperative": 3.2,
    "Agreeableness\/\/Moral": 25.4,
    "Extraversion": 21.7,
    "Extraversion\/\/Sociable": 12,
    "Extraversion\/\/Colorful": 41.5,
    "Extraversion\/\/Friendly": 56.4,
    "Extraversion\/\/Upbeat": 0.7,
    "Extraversion\/\/Thrill-seeking": 69.2,
    "Stability": 24.4,
    "Stability\/\/Inattentive": 64.4,
    "Stability\/\/Resilient": 5.4,
    "Stability\/\/Composed": 63.8,
    "Stability\/\/Calm": 35.8,
    "Stability\/\/Positive": 0.1,
    "Drive": 70,
    "Drive\/\/Confident": 72.4,
    "Drive\/\/Proactive": 76.9,
    "Drive\/\/Leading": 64.5,
    "Drive\/\/Competitive": 38.2,
    "Drive\/\/Goal-oriented": 72.8,
    "Conscientiousness": 11.7,
    "Conscientiousness\/\/Organized": 14.1,
    "Conscientiousness\/\/Cautious": 42.6,
    "Conscientiousness\/\/Self-disciplined": 14.1,
    "Conscientiousness\/\/Dutiful": 1.8,
    "Conscientiousness\/\/Perfectionist": 56.2,
    "Considerate": 26.6,
    "Candid": 73.4,
    "Disciplined": 11.7,
    "Flexible": 88.3,
    "Driven": 70,
    "Laid-back": 30,
    "Outgoing": 21.7,
    "Reserved": 78.3,
    "Curious": 40.8,
    "Pragmatic": 59.2,
    "Stable": 24.4,
    "Passionate": 75.6
  },
  "assessment": {
    "formId": "XSu8loe2Ai",
    "name": "CDP Local"
  },
  "account": {
    "name": "Deeper Signals",
    "indexName": "deepersignals"
  },
  "event": "AssessmentFinished"
}
Status 200 OK
{
  "id": 1,
  "email": "test@example.com",
  "first_name": "test",
  "last_name": "twae",
  "created_at": "2020-11-08 19:18:00",
  "account": {
    "name": "Deeper Signals",
    "index_name": "deepersignals"
  },
  "event": "UserCreated"
}
Status 200 OK
{
  "id":1,
  "email": "test@example.com",
  "first_name": "test",
  "last_name": "twae",
  "created_at": "2020-11-08 19:18:00",
  "account": {
    "name": "Deeper Signals",
    "index_name": "deepersignals"
  },
  "event": "UserDeleted"
}