Active Directory Federated Services (ADFS) has come a long way since the first builds I worked with many years ago. It is almost a de facto federation platform for many organizations when using on-premises or cloud services such as SharePoint and SharePoint Online. The main reason for utilizing a federated platform is to primarily provide single sign-on across multiple platforms and allow other users not within our organization to access internal resources.

To facilitate this, Active Directory Federated Services (ADFS) utilizes Claims that return specific values to present at the application level for authorization. A standard user flow has the internal or external user browse the required resource first, such as SharePoint. Next, they are sent to ADFS to send them to the required authentication service, such as Active Directory (AD). It could be internal or to ADFS or external at another organization. After the authentication completes, ADFS then creates the claims needed and sends the user into the application where authorization completes.

Claims within Active Directory Federated Services (ADFS) can either retrieve values from Active Directory (AD) or some other configured provider such as a Database service like Microsoft SQL Server.

The claims rule language is powerful and allows you to create complex queries and claims needed for the application. You can also craft claims using rules based on a specific format.

For example, a simple rule to retrieve all claims available looks like this:

=> issue(claim = c);

A more advanced claim rule could look like this (Creation of a single claim by using three rules):

c:[Type == "", Issuer == "AD AUTHORITY"]
=> add(store = "Active Directory", types = (""), query = ";memberOf;{0}", param = c.Value);

c:[Type == ""]
=> add(Type = "", Value = RegExReplace(c.Value, ",[^\n]*", ""));

c:[Type == ""]
=> issue(Type = "", Value = RegExReplace(c.Value, "^CN=", ""));

Since Active Directory Federated Services (ADFS) 2016 (the version on Server 2016 and above), you can craft claims using JSON (JavaScript Object Notation) when using SAML-P (Security Assertion Markup Language) version 2, not WS-Federation. Natively JSON provides a lightweight way of presenting and retrieving data. It is ideal for sending values as data objects within all applications and services.

JSON, in its simplest form, looks similar to this:

	"Category" : [{
			"Property" : "Value"
	"Property" : "Value"

The advantage to using JSON is that we can nest multiple values in structures such as arrays. Using this format within claims allows the creation of complex claims that return multiple values.

Creating JSON claims requires using the Active Directory Federated Services (ADFS) claims language. The JSON you could use could be like this:

  "Groups": [
    "All Users",
    "External Users",
    "SharePoint Access"

Converting this to claims requires it to look like this:

{\x22Groups\x22:[\x22All Users\x22,\x22External Users\x22,\x22SharePoint Access\x22]}

The actual Active Directory Federated Services (ADFS) rule then looks like this:

=> issue(Type = "Security Groups", ValueType = "", Value = "{\x22Groups\x22:[\x22All Users\x22,\x22External Users\x22,\x22SharePoint Access\x22]}");

With the rule created when authenticating over SAML-P (version 2), the claims rule executes and returns a claim in this format.

The downside here is that the ending application needs to know what to do with the returned values in the claim. For example, if I am authenticating through Active Directory Federated Services (ADFS) and the resource is SharePoint On-premises, we need to write custom code to utilize these values. Though we need to do that, using JSON within claims seems a powerful option for passing data around within claims. A final example could be to send multiple attributes and values together in a single claim like the one below:

      "firstname" : "James",
      "lastname" : "Brown",
      "fullname": "James Brown",
      "email": "",
      "image": "jb.jpg",
      "jobTitle": "Security Research Assistant",
      "alumniOf": "Dartmouth",
      "birthPlace": "Philadelphia, PA",
      "birthDate": "1980-10-12",
      "gender": "male",
      "nationality": "United States",
      "telephone": "(123) 456-6789",
      "clearance" : "TS/SCI",
      "address": {
        "addressLocality": "Colorado Springs",
        "addressRegion": "CO",
        "postalCode": "80840",
        "streetAddress": "100 Main Street"

The claims rule would now look like this:

=> issue(Type = "UserProperties", ValueType = "", Value = "{\x22firstname\x22:\x22James\x22,\x22lastname\x22:\x22Brown\x22,\x22fullname\x22:\x22James Brown\x22,\x22email\x22:\\x22,\x22image\x22:\x22jb.jpg\x22,\x22jobTitle\x22:\x22Security Research Assistant\x22,\x22alumniOf\x22:\x22Dartmouth\x22,\x22birthPlace\x22:\x22Philadelphia, PA\x22,\x22birthDate\x22:\x221980-10-12\x22,\x22gender\x22:\x22male\x22,\x22nationality\x22:\x22United States\x22,\x22telephone\x22:\x22(123) 456-6789\x22,\x22clearance\x22:\x22TS/SCI\x22,\x22address\x22:{\x22addressLocality\x22:\x22Colorado Springs\x22,\x22addressRegion\x22:\x22CO\x22,\x22postalCode\x22:\x2280840\x22,\x22streetAddress\x22:\x22100 Main Street\x22}}");

The ending result within the claims is this: