Sascha Preibisch

HowTo - Update - Integrate using SAML instead of JWT

Blog Post created by Sascha Preibisch Employee on Oct 4, 2016

Update - How to use SAML instead of JWT to integrate with an external Login-Server

After I was asked if SAML could be used instead of JWT and I have said yes, of course, I was asked several times to provide an example on how to do that. If have now implemented it and can share how it works.


First of all, whenever you want to start modifying something in OTK such as replacing JWT with SAML DO NOT do it in the OTK policies! That is way too complicated. Instead, create a sample API, copy the JWT parts out of the policy and put them into this new API. Use a tool such as Postman or SOAPUI and get that API working. Set sample values wherever you want. Once that is done, start replacing the bits and pieces that you want to swap until its working. After you did that, put those policy snippets into the OTK policies. Doing it this way makes troubleshooting way simpler.


What to do

You have to update policies at 7 locations. Luckily its almost always the same so you could create policy fragments and re-use them. In this guide we will simply copy and paste the same pieces. You have to have a private key to sign the SAML and you need a public cert for the encryption. In this example, I have created a private key and referenced it for both. In your environment you would import the public certificate of the login-server, the login-server would import your gateways public certificate to validate signatures.


First step:

/auth/oauth/v2/authorize, 1 single location: Create the initial SessionData variable

At line number 117 the policy uses an Encode Json Web Token: sign payload assertion. That has to be replaced with the following:


SAML instead of JWT


Line 118: Base64 encode the existing session data which is a JSON structure

Line 119: The SAML assertion requires a credential context. Since no user is involved and this SAML assertion is not about users but carrying data I used the URL of the login-server as username. The receiving API will check for that value.

Line 120: Create the SAML assertion using the private key odic (select one available in your system)

Line 121: Base64 encode the created SAML assertion XML message. Although we are not using JWT I kept the variable names to require less modifications. If you plan to not do JWT at all you may want to change the names to make it less confusing when looking at the policy in a few months (or even a few weeks) time

Line 122: URL Encode the string


For line 120, this is how you can configure it when going through the assertion creation wizard:

  • Step 2: SAML Version:  Version 2
  • Step 3: Issuer: select X.509 Subject Name, Issuer Value: Default
  • Step 4: SAML Statement: Attribute Statement
  • Step 6: Add the following attribute (and leave everything with default values):
    • Attribute Name: sessionData
    • Attribute Name Format: Basic
    • Attribute Value: ${sessionDataB64}
  • Step 7: Name Identifier: Include Name Identifier, Format: automatic, Name Identifier Value: From Credentials
  • Step 8: Subject Confirmation
    • Subject Confirmation Method: Bearer
    • Subject Confirmation Data: ${location_login_server}
  • Step 9: Conditions: Use Default Validity Period, Audience Restriction: ${location_login_server}
  • Step 10: Digital Signatures: Sign Assertion with an Enveloped Signature


This API is ready to go. As you can see, a few more lines then before but in the end very straight forward. Remember that you may want to configure your SAML assertion differently, this is just an example.


Next stop:

/auth/oauth/v2/authorize/login, 3 locations, Validate and create SAML

This API receives the SAML token created at the previous API. It has to validate it and, after the user has been authenticated, create a new one which has to be signed and partially encrypted. 2 of these 3 locations will use exactly the same policy snippet. In the original policy look for lines 50, 99 and 162. You can also search for JSON Web Token to find the JWT assertions.



In the original policy replace lines 50, 51 and 99, 100 with the following:


SAML instead of JWT


Line 51: Base64 decode the received SAML token. URL encoding is done by the gateway automagically. The created variable is of type XML

Line 52: Validate the SAML token

Line 53: Decode the session data into the variable sessionData of type application/json


For line 52 (and 104 after inserting these lines), this is how you can configure it when going through the assertion creation wizard:

  • SAML Version: Version 2.x
  • Attribute Statement:
    • Attribute Name: sessionData
    • Attribute Name Format: Basic
    • Attribute Value: Allow any non-empty value
  • Subject Confirmation: Method: Bearer, Recipient: ${location_login_server}, Check Validity Period
  • Name Identifier: Unspecified
  • Conditions: Audience Restriction: ${location_login_server}
  • Embedded Signature: Require Embedded Signature


As I said, configure this once and use it at both locations.



Now we have to create a SAML token. After modifying the 2 policy locations above we will continue at line 168 (which has been 162 in the original policy, Encode Json Web Token: sign & encrypt payload). As I said earlier, the SAML policy snippets are used multiple times.


Below is the new policy snippet to create the signed and encrypted SAML token. I will only explain the differences compared to the one at /auth/oauth/v2/authorize:

SAML instead of JWT


Line 169: Encode the variable sessionData instead of session 

Line 170, 171: Reference the variable location_consent_server instead of location_login_server

Line 172: Overwrite the variable issuedSamlAssertion to issuedSamlAssertion, use message type XML. This turns a string into a message which is needed at line 173

Line 173: Encrypt the sessionData. Please note that you may want to encrypt more parts of the message. In this example I only encrypt the sessionData itself


For line 173, this is how you can configure it when going through the assertion creation wizard:

  • Elements: /saml2:Assertion/saml2:AttributeStatement/saml2:Attribute/saml2:AttributeValue
  • Encryption method: choose one that is good for your environment. I did not worry about it for this example and used this one:
  • Specify certificate: from the menu select the public certificate your login server provided for encryption. It must have been imported into the gateway first. In my case I selected my example private key as the source
  • Do a right-click and configure the target message to be: issuedSamlAssertion


Last stop

/auth/oauth/v2/authorize/consent, 3 locations, just one new implementation

This policy has to validate the SAML and decrypt the sessionData element. It also has to create it. 


Search for the occurences of Decode Json Web Token. They will come in pairs, one is decrypting the JWT, the other is checking the signature. Replace both pairs to look like this:

SAML instead of JWT


As you may see it is the same as on lines 50, 51 that we have created earlier. The only addition is the decrypt assertion on line 49. That assertion only requires one piece of configuration in the dialog:

  • XPath to encrypted element: /saml2:Assertion/saml2:AttributeStatement/saml2:Attribute/xenc:EncryptedData

Also, do a right-click and configure the target message to be: samlBearer


The remaining JWT assertion is Encode Json Web Token: sign & encrypt payload. Replace that line (64 originally) with this:

SAML instead of JWT


Guess what? It is exactly the same as before! Lines 67 - 74 match lines 168 - 175 further up.



You can now integrate with an external login-server using SAML instead of JWT. Use this example and apply any modifications as you need them. In addition to API tests I have used the Safari browser with the OTK browser based test clients to verify that its working. I had some trouble using Chrome (displaying an empty screen) but I did not want to postpone this post cause of debugging purposes. Maybe you can let me know what the problem is :-)


I hope this helps!