How to: Request a Token from ACS via the OAuth WRAP Protocol

Applies To

  • Microsoft Azure Active Directory Access Control (also known as Access Control Service or ACS)

Overview

When your web applications and services handle authentication using ACS, the client must obtain a security token issued by ACS to log in to your application or service. In order to obtain this ACS-issued token (output token), the client must either authenticate directly with ACS or send ACS a security token issued by its identity provider (input token). ACS validates this input security token, processes the identity claims in this token through the ACS rules engine, calculates the output identity claims, and issues an output security token.

This topic describes the methods of requesting a token from ACS via the OAuth WRAP protocol. All token requests via the OAuth WRAP protocol are transmitted over SSL. ACS always issues a Simple Web Token (SWT) via the OAuth WRAP protocol, in response to a correctly formatted token request. All token requests via the OAuth WRAP protocol are sent to ACS in an HTTP POST. You can request an ACS token via the OAuth WRAP protocol from any platform that can make an HTTPS FORM POST: .NET Framework, Windows Communication Foundation (WCF), Silverlight, ASP.NET, Java, Python, Ruby, PHP, Flash, and other platforms.

The following table lists three supported methods of requesting an ACS-issued SWT token via the OAuth WRAP protocol.

Three methods of requesting a token from ACS via the OAuth WRAP protocol

Token request method Description

Password token requests

This simplest method requires the client to send a user name and password from a service identity directly to ACS via the OAuth WRAP protocol for authentication.

SWT token requests

This method requires the client to send a SWT token which can be signed with a service identity symmetric key or an identity provider symmetric key to ACS via the OAuth WRAP protocol for authentication.

SAML token requests

Intended primarily for Active Directory Federation Service (AD FS) 2.0 integration, the Security Assertion Markup Language (SAML) method requires the client to send a signed SAML token to ACS via the OAuth WRAP protocol for authentication. This approach allows the client to use an enterprise identity to authenticate with ACS.

Token issuing endpoint

All ACS token requests via the OAuth WRAP protocol are directed at an ACS token-issuing endpoint. The URI of this endpoint depends on the Access Control namespace. The namespace appears as a DNS name prefix in a token request URI. The rest of the DNS name is fixed, as is the path. For example, if you want to request a token from the Access Control namespace called "mysnservice", you can direct a token request to the following URI: https://mysnservice.accesscontrol.windows.net/WRAPv0.9.

Password token requests

With a password token request, a client can send a user name and password from a service identity directly to ACS via the OAuth WRAP protocol for authentication. This is the easiest way to request a token from ACS using the OAuth WRAP protocol. Other than establishing an SSL connection, this approach requires no cryptographic capability. In practice, it is similar to the username/password model that is prevalent in REST Web services. This type of token request is actually an HTTPS form POST. The parameters in a password token request are form-encoded.

The following is an example of a wire trace of a plaintext request to a namespace called “mysnservice”.

POST /WRAPv0.9/ HTTP/1.1
Host: mysnservice.accesscontrol.windows.net
Content-Type: application/x-www-form-urlencoded

wrap_scope=http%3A%2F%2Fmysnservice.com%2Fservices%2F&
wrap_name=mysncustomer1&
wrap_password=5znwNTZDYC39dqhFOTDtnaikd1hiuRa4XaAj3Y9kJhQ%3D

The table below provides the names, descriptions, and value requirements of the parameters that are required to be present in a password token request:

Parameter name Description Value requirements

wrap_scope

Matches the token request against a set of rules. Set the value of this parameter to the value of the relying party application realm. You can obtain this value (in the Realm field) through the ACS Management Portal by selecting the appropriate relying party application from the Relying Party Applications page.

  • HTTP or HTTP(s) URI

  • No query parameters or anchors.

  • Path segments <= 32.

  • Maximum length: 256 characters.

  • Must be URL-encoded.

wrap_name

Validates the key of the next parameter. Set the value of this parameter to the name of a service identity within your Access Control namespace. You can obtain this value (in the Name field) through the ACS Management Portal by selecting the appropriate service identity from the Service Identities page.

  • Minimum length: 1 character.

  • Maximum length: 128 characters.

  • Must be URL-encoded.

wrap_password

Authenticates the incoming request. Set the value of this parameter to the password of a service identity within your Access Control namespace. You can obtain this value (in the Password field on the Edit Credential page), through the ACS Management Portal, by first selecting the appropriate service identity on the Service Identities page, and then selecting the appropriate password in the Credentials table on the Edit Service Identity page.

  • String, minimum of 1 and maximum of 64 characters in length.

  • Must be URL-encoded.

The values of these parameters must be URL-encoded before you send the request to ACS. Your web application or service can provide the value of the wrap_scope to the client, or the client can decide to set the value of the wrap_scope parameter to the URI of the web application or service resource target.

Password token requests via the OAuth WRAP protocol can also contain additional parameters which ACS can use during the output claim calculation process. These additional parameter names and values must be URL-encoded and values must not be quoted.

The password token request method is fairly straightforward using .

WebClient client = new WebClient();
client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");

NameValueCollection values = new NameValueCollection();
values.Add("wrap_name", "mysncustomer1");
values.Add("wrap_password", "5znwNTZDYC39dqhFOTDtnaikd1hiuRa4XaAj3Y9kJhQ=");
values.Add("wrap_scope", "http://mysnservice.com/services");

// WebClient takes care of the URL Encoding
byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);

// the raw response from ACS
string response = Encoding.UTF8.GetString(responseBytes);

For information on how to unpack the output token from ACS and send it to the web application or service, see Unwrapping and sending the token to a web application or service.

SWT token requests

You can also request a token from ACS via the OAuth WRAP protocol using a SWT token signed by a symmetric key. All SWT token requests are made through an HTTPS form POST. The parameter values in this token request method are form-encoded.

The following is an example of a wire trace of a SWT token request to the "mysnservice" namespace.

POST /WRAPv0.9/ HTTP/1.1
Host: mysnservice.accesscontrol.windows.net
Content-Type: application/x-www-form-urlencoded

wrap_scope=http%3A%2F%2Fmysnservice.com%2Fservices%2F&
wrap_assertion_format=SWT&
wrap_assertion=Issuer%3dmysncustomer1%26HMACSHA256%3db%252f%252bJFwbngGdufECFjQb8qhb9YH0e32Cf9ABMDZFiPPA%253d

A SWT token request must have the following parameters and values:

Parameter name Description Value requirements

wrap_scope

Matches the token request against a set of rules.

  • Set the value of this parameter to the value of the relying party application realm. You can obtain this value (in the Realm field) through the ACS Management Portal by selecting the appropriate relying party application from the Relying Party Applications page.

  • HTTP or HTTP(s) URI.

  • No query parameters or anchors.

  • Path segments <= 32.

  • Maximum length: 256 characters.

  • Must be URL encoded.

wrap_assertion

This is the input token that is being sent to ACS.

  • A signed SWT token with input claims that include issuer and HMACSHA256 parameters.

  • Maximum length: 2048 characters.

  • Must be URL encoded.

wrap_assertion_format

This is the format of the input token that is being sent to ACS.

SWT

As shown in the following example, the code that is required to make a SWT token request resembles the code that is required to make a password token request.

WebClient client = new WebClient();
client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");

NameValueCollection values = new NameValueCollection();
// add the wrap_scope
values.Add("wrap_scope", "http://mysnservice.com/services");
// add the format
values.Add("wrap_assertion_format", "SWT");
// add the SWT
values.Add("wrap_assertion", "Issuer=mysncustomer1&HMACSHA256=b%2f%2bJFwbngGdufECFjQb8qhb9YH0e32Cf9ABMDZFiPPA%3d");
// WebClient takes care of the remaining URL Encoding
byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);

// the raw response from ACS
string response = Encoding.UTF8.GetString(responseBytes);

For information on how to unpack the response from ACS and send it to your web application or service, see Unwrapping and sending the token to a web application or service.

Creating a SWT token

A SWT token is a set of key/value pairs that are signed with an issuer key (a symmetric key). A SWT token sent to ACS in a SWT token request, must contain the Issuer and HMACSHA256 parameters, as well as additional parameters, for example, ExpiresOn, Audience, and other client-specific claims. The following table provides the names and descriptions of SWT token parameters:

Parameter name Description

Issuer

In ACS, looks up the key that was used to sign the token. If the signature is valid, then this value is used to perform output claim calculation.

You can set this parameter to the value of the realm of an identity provider within your Access Control namespace or the name of a service identity within your Access Control namespace. You can obtain this value (in the Realm field on the Edit Identity Provider page) via the ACS Management Portal, by selecting the appropriate identity provider on the Identity Providers page. Or you can obtain this value via the ACS Management Service – this is the name property of the “Issuer” record that is created for each identity provider.

HMACSHA256

In ACS, validates the SWT signature and looks up the issuer key named in the Issuer parameter.

The SWT signature is created using the symmetric signing key attached to a service identity or an identity provider within your Access Control namespace.

Audience

If present, ACS uses this value to make sure that ACS is the intended target of the SWT token. This is the URL of your Access Control namespace, for example, https://contoso.accesscontrol.windows.net/

ExpiresOn

If present (in Epoch time), indicates whether the token is expired. For example, the value of this parameter can be 1324300962.

Additional claims

If present, ACS uses these parameters to perform output claim calculation. Each claim type must appear only one time. Multiple claim values of the same claim type must be concatenated together with a "," (comma) character. For more information about asserting claims in ACS, see Claims assertion via the OAuth WRAP protocol.

The following code sample shows how to generate an SWT token using . It contains a type that builds SWT tokens that contain the Issuer and HMACSHA256 parameters.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;

public class TokenFactory
{
    string signingKey;   
    string issuer;
    
    public TokenFactory(string issuer, string signingKey)
    {
        this.issuer = issuer;
        this.signingKey = signingKey;
    }

    public string CreateToken()
    {
        StringBuilder builder = new StringBuilder();

        // add the issuer name
        builder.Append("Issuer=");
        builder.Append(HttpUtility.UrlEncode(this.issuer));

        string signature = this.GenerateSignature(builder.ToString(), this.signingKey);
        builder.Append("&HMACSHA256=");
        builder.Append(signature);

        return builder.ToString();
    }

   
    private string GenerateSignature(string unsignedToken, string signingKey)
    {
        HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(signingKey));

        byte[] locallyGeneratedSignatureInBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(unsignedToken));

        string locallyGeneratedSignature = HttpUtility.UrlEncode(Convert.ToBase64String(locallyGeneratedSignatureInBytes));

        return locallyGeneratedSignature;
    }
}

SAML token requests

The SAML token request method is intended mainly for the AD FS 2.0 integration and allows the client to use an enterprise identity (Active Directory) to authenticate with ACS. With the SAML token request method, you can send a signed SAML 1.1 or a SAML 2.0 token issued by AD FS 2.0 (input token) to ACS via the OAuth WRAP protocol.

ACS uses its rules to calculate the output claims, groups them into a SWT token (output token), signs it, and returns it to the client via the OAuth WRAP protocol.

A SAML token request must have the following parameters and values:

Parameter name Description Value requirements

wrap_scope

Matches the token request against a set of rules.

  • Set the value of this parameter to the value of the relying party application realm. You can obtain this value (in the Realm field) through the ACS Management Portal by selecting the appropriate relying party application from the Relying Party Applications page.

  • HTTP or HTTP(s) URI.

  • No query parameters or anchors.

  • Path segments <= 32.

  • Maximum length: 256 characters.

  • Must be URL encoded.

wrap_assertion

This is the input token that is being sent to ACS.

  • A signed SAML 1.1 or 2.0 token with input claims. SAML 1.1 tokens, as a token limitation, require at least one input claim. This means that either an identity provider or a claims-enabled service identity must be used for SAML 1.1 token authentication. SAML 2.0 tokens do not require any input claims for authentication against a service identity, aside from the implicit NameIdentifier claim, therefore SAML 2.0 tokens can be used to authenticate against a normal service identity that is not claims-enabled.

  • Must be URL encoded.

wrap_assertion_format

This is the format of the input token that is being sent to ACS.

SAML

The following is an example of the code that is required to make a SAML token request.

private static string SendSAMLTokenToACS(string samlToken)
{
 try
 {
  WebClient client = new WebClient();
  client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");
  NameValueCollection parameters = new NameValueCollection();
  parameters.Add("wrap_assertion_format", "SAML");
  parameters.Add("wrap_assertion", samlToken);
  parameters.Add("wrap_scope", "http://mysnservice.com/services");

  byte[] responseBytes = client.UploadValues("WRAPv0.9", parameters);
  string response = Encoding.UTF8.GetString(responseBytes);

  return response
   .Split('&')
   .Single(value => value.StartsWith("wrap_access_token=", StringComparison.OrdinalIgnoreCase))
   .Split('=')[1];
 }
 catch (WebException wex)
 {
  string value = new StreamReader(wex.Response.GetResponseStream()).ReadToEnd();
  throw;
 }
}  

For information on how to unpack the response from ACS and send it to your web application or service, see Unwrapping and sending the token to a web application or service.

Claims assertion via the OAuth WRAP protocol

To enable backwards compatibility with ACS 1.0 token request behavior, ACS supports the ability to assert claims as part of token requests.

Register the asserting application or service as an ACS identity provider.

The recommended way to do this is to register the asserting application or service as an ACS identity provider. Then the application or service requests a token from ACS by presenting a SAML or SWT token that contains the claims that it wants to assert, and this token is signed using an Identity Provider Key stored in ACS. For example, you can send a SAML token request with asserted claims to ACS via the OAuth WRAP protocol from AD FS 2.0 or any custom Security Token Service (STS) that is built using Windows Identity Foundation (WIF) and registered in ACS as a WS-Federation identity provider.

You can use the ACS Management Portal to register an identity provider using WS-Federation metadata, or you can use the ACS Management Service to individually set identity provider properties, addresses, and keys. (For example, see How to: Use ACS Management Service to Configure AD FS 2.0 as an Enterprise Identity Provider.) No service identities are required in this method of asserting claims in a token request. This method is functional via all ACS-supported protocols.

Unwrapping and sending the token to a web application or service

If the token request is successfully authenticated, ACS returns two form-encoded parameters: wrap_token and wrap_token_expires_in. The values of these parameters are the actual SWT token that the client can use to gain access to your web application or service and the approximate remaining lifetime of this token (in seconds), respectively.

Before sending the SWT token to the web application or service, the client must extract and URL-decode it from the ACS response. If the web application or service requires the token to be presented in the HTTP Authorization header, the token must be preceded by the scheme WRAPv0.9.

The following code example demonstrates how to unpack a token and format the Authorization header.

WebClient client = new WebClient();
client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");

NameValueCollection values = new NameValueCollection();
values.Add("wrap_name", "mysncustomer1");
values.Add("wrap_password", "5znwNTZDYC39dqhFOTDtnaikd1hiuRa4XaAj3Y9kJhQ=");
values.Add("wrap_scope", "http://mysnservice.com/services");

// WebClient takes care of the URL Encoding
byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);

// the raw response from ACS
string response = Encoding.UTF8.GetString(responseBytes);

string token = response
    .Split('&')
    .Single(value => value.StartsWith("wrap_token=", StringComparison.OrdinalIgnoreCase))
    .Split('=')[1];

string.Format("WRAP access_token=\"{0}\"", HttpUtility.UrlDecode(token));

ACS Error Codes and Descriptions

ACS returns errors when it cannot satisfy a token request. In keeping with the REST design, the error contains an HTTP response code. In many cases, ACS errors also contain a SubCode and Detail that provide context about what failed. The error format is: Error:Code:<httpStatus>:Sub-Code:<code>:Detail:<message>. The Content-Type of an error is always text/plain.

HTTP/1.1 401 Access Forbidden
Content-Type: text/plain; charset=us-ascii

Error:Code:401:SubCode:T0:Detail:ACS50009: SWT token is invalid. :TraceID:<trace id value>:TimeStamp:<timestamp value>

For more information on ACS error codes, see ACS Error Codes.

When debugging or recovering from an error returned from ACS, it is often required to read the response body. The following code example shows how to read the error message from a WebException object.

try
{
    WebClient client = new WebClient();
    client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");

    NameValueCollection values = new NameValueCollection();
    values.Add("wrap_name", "mysncustomer1");
    values.Add("wrap_password", "5znwNTZDYC39dqhFOTDtnaikd1hiuRa4XaAj3Y9kJhQ=");
    values.Add("wrap_scope", "http://mysnservice.com/services");

    // WebClient takes care of the URL Encoding
    byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);

    // the raw response from ACS
    string response = Encoding.UTF8.GetString(responseBytes);

    string token = response
        .Split('&')
        .Single(value => value.StartsWith("wrap_access_token=",       StringComparison.OrdinalIgnoreCase))
        .Split('=')[1];
}
catch (WebException wex)
{
    if (wex.Response != null)
    {
        // the response Stream contains the error message
        StreamReader reader = new StreamReader(wex.Response.GetResponseStream());
        string message = reader.ReadToEnd();
    }
    // Throw as appropriate
}

See Also

Concepts

ACS How To's