Special Configuration Scenarios: Signing and Encrypting SAML Requests

To increase the security of your transactions, you can sign or encrypt both your requests and your responses.

Sign the SAML Authentication Request

If Auth0 is the SAML service provider, you can sign the authentication request Auth0 sends to the IdP as follows:

  1. For the Connection in which you're interested, navigate to Enterprise -> SAMLP Identity Provider -> Settings.
  2. Enable the Sign Request toggle.
  3. Download the certificate beneath the Sign Request toggle and provide it to the IdP so that it can validate the signature.

Enable/Disable Deflate Encoding

By default, SAML authentication requests are sent via HTTP-Redirect and use deflate encoding, which puts the signature in a query parameter.

To turn off deflate encoding, you can make a PATCH call to the Management API's Update a Connection endpoint and set the deflate option to false.


curl --request PATCH \
  --url 'https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID' \
  --header 'authorization: Bearer MGMT_API_ACCESS_TOKEN' \
  --data '{ "name": "CONNECTION_NAME", "options": "{"validation": "object", "passwordPolicy": "", "password_history": "object", "password_no_personal_info": "object", "password_dictionary": "object", "deflate": "false",}" }'
var client = new RestClient("https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID");
var request = new RestRequest(Method.PATCH);
request.AddHeader("authorization", "Bearer MGMT_API_ACCESS_TOKEN");
request.AddParameter("undefined", "{ \"name\": \"CONNECTION_NAME\", \"options\": \"{\"validation\": \"object\", \"passwordPolicy\": \"\", \"password_history\": \"object\", \"password_no_personal_info\": \"object\", \"password_dictionary\": \"object\", \"deflate\": \"false\",}\" }", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID"

	payload := strings.NewReader("{ \"name\": \"CONNECTION_NAME\", \"options\": \"{\"validation\": \"object\", \"passwordPolicy\": \"\", \"password_history\": \"object\", \"password_no_personal_info\": \"object\", \"password_dictionary\": \"object\", \"deflate\": \"false\",}\" }")

	req, _ := http.NewRequest("PATCH", url, payload)

	req.Header.Add("authorization", "Bearer MGMT_API_ACCESS_TOKEN")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.patch("https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID")
  .header("authorization", "Bearer MGMT_API_ACCESS_TOKEN")
  .body("{ \"name\": \"CONNECTION_NAME\", \"options\": \"{\"validation\": \"object\", \"passwordPolicy\": \"\", \"password_history\": \"object\", \"password_no_personal_info\": \"object\", \"password_dictionary\": \"object\", \"deflate\": \"false\",}\" }")
  .asString();
var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID",
  "method": "PATCH",
  "headers": {
    "authorization": "Bearer MGMT_API_ACCESS_TOKEN"
  },
  "data": "{ \"name\": \"CONNECTION_NAME\", \"options\": \"{\"validation\": \"object\", \"passwordPolicy\": \"\", \"password_history\": \"object\", \"password_no_personal_info\": \"object\", \"password_dictionary\": \"object\", \"deflate\": \"false\",}\" }"
}

$.ajax(settings).done(function (response) {
  console.log(response);
});
var request = require("request");

var options = { method: 'PATCH',
  url: 'https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID',
  headers: { authorization: 'Bearer MGMT_API_ACCESS_TOKEN' },
  body: '{ "name": "CONNECTION_NAME", "options": "{"validation": "object", "passwordPolicy": "", "password_history": "object", "password_no_personal_info": "object", "password_dictionary": "object", "deflate": "false",}" }' };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"authorization": @"Bearer MGMT_API_ACCESS_TOKEN" };

NSData *postData = [[NSData alloc] initWithData:[@"{ "name": "CONNECTION_NAME", "options": "{"validation": "object", "passwordPolicy": "", "password_history": "object", "password_no_personal_info": "object", "password_dictionary": "object", "deflate": "false",}" }" dataUsingEncoding:NSUTF8StringEncoding]];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"PATCH"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "PATCH",
  CURLOPT_POSTFIELDS => "{ \"name\": \"CONNECTION_NAME\", \"options\": \"{\"validation\": \"object\", \"passwordPolicy\": \"\", \"password_history\": \"object\", \"password_no_personal_info\": \"object\", \"password_dictionary\": \"object\", \"deflate\": \"false\",}\" }",
  CURLOPT_HTTPHEADER => array(
    "authorization: Bearer MGMT_API_ACCESS_TOKEN"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
import http.client

conn = http.client.HTTPSConnection("")

payload = "{ \"name\": \"CONNECTION_NAME\", \"options\": \"{\"validation\": \"object\", \"passwordPolicy\": \"\", \"password_history\": \"object\", \"password_no_personal_info\": \"object\", \"password_dictionary\": \"object\", \"deflate\": \"false\",}\" }"

headers = { 'authorization': "Bearer MGMT_API_ACCESS_TOKEN" }

conn.request("PATCH", "/YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Patch.new(url)
request["authorization"] = 'Bearer MGMT_API_ACCESS_TOKEN'
request.body = "{ \"name\": \"CONNECTION_NAME\", \"options\": \"{\"validation\": \"object\", \"passwordPolicy\": \"\", \"password_history\": \"object\", \"password_no_personal_info\": \"object\", \"password_dictionary\": \"object\", \"deflate\": \"false\",}\" }"

response = http.request(request)
puts response.read_body
import Foundation

let headers = ["authorization": "Bearer MGMT_API_ACCESS_TOKEN"]

let postData = NSData(data: "{ "name": "CONNECTION_NAME", "options": "{"validation": "object", "passwordPolicy": "", "password_history": "object", "password_no_personal_info": "object", "password_dictionary": "object", "deflate": "false",}" }".dataUsingEncoding(NSUTF8StringEncoding)!)

var request = NSMutableURLRequest(URL: NSURL(string: "https://YOUR_AUTH0_DOMAIN/api/v2/connections/YOUR_CONNECTION_ID")!,
                                        cachePolicy: .UseProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.HTTPMethod = "PATCH"
request.allHTTPHeaderFields = headers
request.HTTPBody = postData

let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    println(error)
  } else {
    let httpResponse = response as? NSHTTPURLResponse
    println(httpResponse)
  }
})

dataTask.resume()

Sign the SAML Authentication Responses/Assertions

If Auth0 is the SAML identity provider, it can sign responses/assertions with its private key and provide the service provider with the public key/certificate necessary to validate the signature.

To retrieve the certificate you need to send to your IdP from the Management Dashboard:

  1. Go to Clients -> Settings -> Show Advanced Settings.
  2. Scroll to the Certificates section, and click *Download Certificate to obtain the signing certificate you need to provide to your IdP.
  3. Send your certificate to the service provider.

Next, you'll need make sure that the SAML assertion is not signed (you can sign either the assertion or the response, but not both). Here's how to unsign the SAML Assertion:

  1. In the Management Dashboard, navigate to Clients. Find the Client you're interested in go to Addons > SAML2 WEB APP > Settings.
  2. By default, signResponse is true. As such, uncomment this line and set the value to false. Your SAML assertion will no longer be signed.

Receive Signed SAML Authentication Requests

If Auth0 is the SAML identity provider, it can received requests signed with the service provider's private key. Auth0 will then use the service providers' public key/certificate to validate the signature.

To configure signature validation, you'll need to download the service provider's public key and store the value in the signingCert key. You can find the signingCert field in the Management Dashboard by going to Clients > Addons > SAML2 WEB APP > Settings.

Receive Signed SAML Authentication Responses

If Auth0 is the SAML service provider, all SAML responses from your identity provider should be signed to indicate it hasn't been tampered with by an unauthorized third-party.

You will then need to configure Auth0 to validate the responses' signatures by:

  • Obtaining a signing certificate from the IdP
  • Loading the certificate from the IdP into your Auth0 Connection (in the Management Dashboard, go to the Upload Certificate section for your Connection by navigating to Connections -> Enterprise -> SAMLP Identity Provider -> Settings)

Auth0 can accept a signed response for the assertion, the response, or both.

Send Encrypted SAML Authentication Assertions

If Auth0 is the SAML identity provider, you can use Rules to encrypt the SAML assertions it sends.

You'll need to obtain the public key/certificate from the service provider.

Here is a sample snippet of Rules code.

function (user, context, callback) {

  context.samlConfiguration = (context.samlConfiguration || {});
  context.samlConfiguration.encryptionPublicKey = "-----BEGIN PUBLIC KEY-----\nMIGf...bpP/t3\n+JGNGIRMj1hF1rnb6QIDAQAB\n-----END PUBLIC KEY-----\n";
  context.samlConfiguration.encryptionCert = "-----BEGIN CERTIFICATE-----\nMII...u84\n-----END CERTIFICATE-----\n";

  callback(null, user, context);
}

Receive Encrypted SAML Authentication Assertions

If Auth0 is the SAML service provider, it may need to receive encrypted assertions from an identity provider. To do this, you must provide Auth0's public key and certificate to the IdP. The IdP encrypts the SAML assertion using the public key and sends it to Auth0, which decrypts it using the private key.

To retrieve the certificate you need to send to your IdP from the Management Dashboard, go to Connections -> Enterprise -> SAMLP Identity Provider and click on the Setup Instructions button next to the connection.

Navigate to the section titled Encrypted Assertions and download the certificate in the format requested by the IdP.