Azure Active Directory (Azure AD) supports an OAuth2 Extension Grant called “SAML Bearer Assertion flow” which allows an application to request an JWT OAuth2 token from Azure AD by providing a SAML Assertion (Token) acquired during an authentication process to a different Authorization Server. As you can imagine in order for this token exchange mechanism to happen, a trust relation between Azure AD and that Authorization Server must have already been established via a process called Federation. A common scenario is a hybrid environment where Active Directory Federation Server (ADFS) is used to federate between an Active Directory on-prem domain with Azure AD.

In this blog post I’ll show how to use Postman to request a SAML token (or SAML Assertion) from ADFS server using WS-Trust protocol and then use that SAML token to exchange for an OAuth2 JWT token from Azure AD. There are a few pre-requisites:

  1. Create an App Registration in Azure AD. For this demo I create a single tenant application and set the default client type to be public by selecting ‘Yes’. If you set ‘No’ on the Default client type, you will also need to provide a secret later on when exchanging a SAML Assertion for the OAuth2 JWT token.
  1. Configure the Application permission with at least a delegated Microsoft Graph ‘User.Read’ permission and grant Admin Consent on the permission.
  2. on-prem domain already federated with Azure AD via ADFS Server.
  3. Testing needs to be done with a domain user account synced to Azure AD.

Performing Token Acquisition

Getting a SAML Assertion from ADFS

  1. The first step in using SAML Assertion Grant flow is to get a SAML Assertion from ADFS (or whoever your Federation IDP is).This is typically done via WS-Trust protocol. There are a couple of ways to find the correct endpoint to send the WS-Trust request to.
    1. Send a Home Realm Discovery request to Azure AD to get the ‘federation_active_auth_url’ value
    2. GET https://login.microsoftonline.com/common/userrealm/user@contoso.com?api-version=1.0
      or
    3. Find the usernamemixed endpoint from ADFS’s Tools Management Console

Note: There are a couple of usernamemixed endpoints, use the WS-Trust 2005 type.

Send the POST request to the federation_active_auth_url (aka usernamemixed endpoint) with the following parameter in PostMan:

As noted, you need to supply your own parameters (username, password, and ADFS usernamemixed URL) in the request on line 25,29, and 30:

Your PostMan set up should look like the following:

HTTP Headers

And if everything goes right you should get a SAML Response from the ADFS Server like the following.

Note: In this case ADFS returns a SAML 1.1 token as indicated in the highlighted Assertion (MajorVersion = 1, MinorVersion = 1)

Exchanging a SAML Token for JWT Token

  1. The second step in the SAML Assertion Grant flow is to exchange the SAML Assertion acquired from ADFS Server for a JWT OAuth2 token from Azure AD.

In PostMan change the response view from the last step to Raw View and search for the substring <saml:Assertion …>….</saml:Assertion>


Copy the entire Assertion substring including the node name and paste it into a Base64 encoder of your choice. I use this online tool to do the encoding. We need to base64-encode this SAML Assertion


Copy out the base64-encoded output. This will be used for the next PostMan request.

Note: It is very important that there should not be any spaces between the different nodes in this Assertion substring when doing the encoding since having the spaces can change the encoded output and can cause unexpected error such as ‘AADSTS50006: Signature verification failed because of an invalid signature’ in the following token exchange step.

Use PostMan to perform the following request:

POST https://login.microsoftonline.com/<tenant name>.onmicrosoft.com/oauth2/v2.0/token

POST Body:

grant_typeurn:ietf:params:oauth:grant-type:saml1_1-bearer
client_idyour Application ID
assertionbase64 encoded SAML Assertion
scopehttps://graph.microsoft.com/.default

And you should get a JWT token from this grant:

Note: I set the grant_type parameter to be “urn:ietf:params:oauth:grant-type:saml1_1-bearer” because this is a SAML 1.1 token/Assertion. If the Authorization server returns a SAML 2.0 token (Version attribute in the Assertion element is “2.0”), the grant_type parameter should be set to “urn:ietf:params:oauth:grant-type:saml2-bearer”.

By default, ADFS Server returns a SAML 1.1 token. To specify the version of the returned SAML token, you can use the TokenType element with the value in the following table in the WS-Trust request body.

SAML Token VersionTokenType Value
1.1 Tokenhttp://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1
2.0 Tokenhttp://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0

source: https://www.oasis-open.org/committees/download.php/16768/wss-v1.1-spec-os-SAMLTokenProfile.pdf

Here is an example of a request for a SAML 2.0 Assertion:

5 3 votes
Article Rating
Subscribe
Notify of
guest
6 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Tony
Tony
September 10, 2020 5:07 am

What client-request-id value in the request headers?

Tony
Tony
September 10, 2020 5:17 am

Thanks, What value I need to choose for “<o:UsernameToken u:Id=””>

Also I am getting “An error occurred (InvalidIdentityToken)” error message. I verified for extra spaces or characters in my <saml:Assertion> but everything looks clean. I am not sure why my base64 encoded value is not working

Last edited 16 days ago by Tony
Tony
Tony
September 10, 2020 5:35 am

Also please provide details about client_id in getting JWT token