See us on Github.

This document is aimed at Talent App Store tenants setting up their identity providers (IdPs).

We love feedback. Please get in touch at abraae@aotal.com.

Overview - principal types

In the world of HR software, we don't just have users - we also have candidates (and other classes of people as well). TAS calls these different classes of people principal types, and allows tenants to control the mappings of identity providers (IdPs) to individual principal types.

For example, as a tenant, you might map:

Well-known SAML attributes

Whenever a principal logs into an SSO-protected app, the app is passed a SAML assertion, containing a number of attributes.

TAS defines two well known sets of attributes - personal detail and role - that apps can examine to be informed about the logged in user.

Personal details attributes are useful apps to customise web pages (e.g., "Welcome, Fred Bloggs"), and/or to populate user records (e.g. when doing just-in-time provisioning of users when they first log in).

Role attributes are useful for apps to do user-based authentication checks, e.g. is this person allowed to see this web page? And if so, what menu items should they see?

As a tenant, you may need to manipulate these well-known attributes. Even for your own IdP, you may be unable to make changes to the attribute that first name is passed in (for example).

Personal details attributes

Personal detail attributes are named "tas.personal.*", and hold the user's given (first) name, family (last) name, email and image. These attributes must be of type string.

Role attributes

Role attributes named "tas.role.*" hold the user's membership of a given role. These attributes must be of type boolean, with a value of true.


The following example shows that the logged in candidate has the name Fred Bloggs, and holds the role "internal".

... <saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified" Name="tas.personal.givenName"> <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Fred</saml:AttributeValue> </saml:Attribute> <saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified" Name="tas.personal.familyName"> <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Bloggs</saml:AttributeValue> </saml:Attribute> <saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified" Name="tas.role.internal"> <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:boolean">true</saml:AttributeValue> </saml:Attribute>

Injecting well-known attributes

As for any other SAML attributes, the well-known attributes may be attached right back at source, by the IdP that principal logged in with. This approach allows you the tenant to use your IdP as a single source of truth about your users, and the roles that they hold.

However TAS also provides mechanisms for you to cause well-known attributes to be injected into the SAML assertion after it has been produced by your IdP, but before it is passed to the SSO app.

Injecting personal detail attributes - mapping document

As a tenant you can set up per-idp mapping documents to convert arbitrarily named incoming SAML attributes to their well-known personal detail equivalents. This is useful when you have limited control over the naming of your SAML attributes.

For example, perhaps tenant acme's idp always attaches first name in an attribute named "acme.first.name", and this can't be easily changed. To work around this, acme could set up a mapping document for that idp like this:

Injecting role attributes - assertion hooks

Tenants can set up assertion hooks to check for patterns in named SAML assertions (email addresses are often used), and conditionally insert role attributes.

As well as injecting roles, assertion hooks can also be used to deny login altogether.

The assertion hooks below:

Injecting role attributes - assertion decorator apps

Specially marked assertion decorator apps are called at login time to allow them to inject role attributes.

As well as injecting roles, session decorator apps can also deny login altogether.

As a tenant, you can choose to install this kind of app and thereby influence the roles any given user has.

For example, TAS makes the following call to an assertion decorator app:

POST /tenants/{tenant}/logins/{pt}/{entityID}/{nameID} Response: [ "alumni" ]

The response indicates to TAS that it should merge in a role attribute for the role "alumni".

Order of operations

TAS performs the above actions in the following order:

  1. Apply mapping document
  2. Apply assertion hooks
  3. Invoke assertion decorator apps (in alphabetical order of app name)

For example:

+------------------+ |external SAML IdP | +------------------+ | ... | incoming SAML attributes: | acme.first.name = Barry | acme.last.name = Barry | acme.email = bg@acme.com | +--------------------+ | attribute mapping | +--------------------+ | | tenant's mapping document: | [ | { | "tas.personal.givenName": "acme.first.name" | }, | { | "tas.personal.familyName": "acme.last.name" | } | ] | | resulting SAML attributes: | tas.personal.givenName = Barry | tas.personal.familyName = Gibb | tas.personal.email = bg@acme.com | +-----------------+ | assertion hooks | +-----------------+ | | tenant's assertion hooks: | [ | { | "injectRoles": { | "condition": { | "attribute": "tas.personal.email", | "wildCard": "*.acme.com" | }, | "roles": [ | "internal" | ] | } | } | ] | | resulting SAML attributes: | tas.personal.givenName = Barry | tas.personal.familyName = Gibb | tas.personal.email = bg@acme.com | tas.role.internal = true | +--------------------------+ | assertion decorator apps | +--------------------------+ | | TAS calls POST /tenants/{tenant}/logins/{pd}/{pt}/{nameID} | Response: | 200 | [ "alumni" ] | | resulting SAML attributes: | tas.personal.givenName = Barry | tas.personal.familyName = Gibb | tas.personal.email = bg@acme.com | tas.role.internal = true | tas.role.alumni = true | +------------------------------+ |TAS session document creation | +------------------------------+

Auto-provisioning considerations for assertion decorators

Auto-provisioning refers to creating users "on the fly", i.e. at the time when they first log in to the app.

To decide whether, and how, to auto-provisioning a new logging in user, an app may look at the well known attributes in the SAML assertion, such as email or roles.

It is possible for an app to be both auto-provisioning and also an assertionDecorator.

In a situation where an assertionDecorator app is asked to decorate the assertion for a user that does not exist in the app, but would due to auto-provisioning were they to log in to the app, then the app should normally decorate the assertion just as if the user had been auto-provisioned.

This sort of situation would arise, for example with a legacy ATS app designed to auto-provision new users and grant them access to a separate candidate search app. In this case, if the user logs in to the search app first, having never visisted the legacy ATS app, then the legacy ATS app (acting as an assertionDecorator) should inject roles (possibly including the right to access the search app) as if the user had instead logged into the ATS first and therefore been auto-provisioned and gained the default permissions.