Web Services
NYC.ID includes a Web services interface that your application must use to supplement SAML 2.0 authentication via the NYC.ID IdP.
The Web services are split into several categories. Click a category link below to learn more about each:
The Web services share several important similarities. They:
- are RESTful,
- require authentication, and
- return data formatted in JavaScript Object Notation (JSON).
To configure authentication, your application requires:
- a username and password, called a service account, and
- a signature, calculated for each request.
Versioning
To invoke the non-default version of a Web service (i.e., Authenticate v2), include application/vnd.nyc.vx in the HTTP "Accept" header, where x is the version number of the API (e.g., 2).
Provisioning a Service Account
Your application requires a username and password to securely communicate with the NYC.ID Web services. This combination of username and password is called a NYC.ID Service Account. You may create a NYC.ID Service Account via the NYC.ID Console.
Authenticating Requests
When accessing NYC.ID Web services, your application's request must contain the following parameters so it can be authenticated:
Parameter Name | Description |
---|---|
userName |
NYC.ID Service Account username |
signature |
Each request must contain a valid request signature, or the request will be rejected. A request signature is calculated using your NYC.ID Service Account password, which is a shared secret known only to you and NYC.ID. |
Optionally, it may also include the following parameter to prevent against replay attacks:
Parameter Name | Description |
---|---|
dateTime |
The current date and time formatted as a Java SimpleDateFormat pattern (MM/dd/yyyy HH:mm or M/d/yy HH:mm) . |
Here are the steps for authenticating requests to NYC.ID Web Services...
Your application:
- constructs a request to NYC.ID Web Services.
- calculates the authentication signature using its NYC.ID Service Account password.
- appends the signature to the request.
- sends the request to NYC.ID.
NYC.ID:
- looks up your application's password using the username in the request.
- calculates a signature from the request data and password using the same algorithm that your application used to calculate the signature.
- considers the request authentic if the signature generated by NYC.ID matches the one sent in your application's request and the dateTime, if sent, is within 15 minutes of the current date and time.
- returns an "unauthorized error" response if the signature doesn't match or the dateTime is greater than 15 minutes of the current dateTime.
Calculating the Authentication Signature
The NYC.ID Web Services use a custom HTTP scheme based on a keyed Hash Message Authentication Code (HMAC)—HMAC-SHA256—for authentication. To create the authentication signature, your application should:
- Concatenate the Web Service HTTP method, relative URL, and parameter values of the request to form a string (StringToSign), following these steps:
- Start with an empty string ("").
- Append the HTTP method.
- Append the path part of the HTTP Request-URI, up to but not including the query string.
- Sort the parameters (e.g., "dateTime", "guid", "userName", "userType") alphabetically by parameter name, then value. Append only the parameter value(s). When creating the signature, your application should not encode these values; however, it must URL encode them in the request.
- Append the value of the Authorization header
- Use your NYC.ID Web services password to calculate the HMAC of that string. Informally, we call this process "signing the request." The algorithm takes as input, two strings—a key and a message.
Algorithm Input Parameters Description key
NYC.ID Service Account password message
UTF-8 encoding of the StringToSign
The algorithm returns as output, a string—the signature. We call the output of the HMAC algorithm the signature, because it simulates the security properties of a real signature.
Algorithm Output Description signature
The output is a base64 encoding of HMAC-SHA256 byte-string. The following pseudo-code illustrates the algorithm to create the signature:
signature = Base64(HMAC-SHA256(password, UTF-8-Encoding-Of(StringToSign)));
Here are some examples of creating a StringToSign from a sample request:
Example One:
Request:GETStringToSign :
/account/api/isEmailValidated.htm?guid=ABCD1234&userName=xxx
GET/account/api/isEmailValidated.htmABC1234xxx
Example Two:
Request:GETStringToSign :
/account/api/getUsers.htm?guids=WXYZ5678&guids=ABCD1234&userName=xxx
GET/account/api/getUsers.htmABCD1234WXYZ5678xxx
Sample Requests
The example NYC.ID service account username and password below will be used to generate a signature for each sample request.
userName |
xxx |
password |
#ktccn/[i(a=j)Pdo&4{S):9=]>6Ewm.s/}}.XX-=<kK'$F][M16TR?AJ3z*g|i^ |
The signature has been calculated using the example username and password (above) and appended to the example requests:
GET https://www1.nyc.gov/account/api/isEmailValidated.htm?guid=ABCD1234&userName=xxx&signature=9b249ba5013256b8f46dc9a1b678699d862a1efc2a1a8bcc3c97ad4c3edac3a2
GET https://www1.nyc.gov/account/api/getUsers.htm?guids=ABCD1234&userName=xxx&signature=d11be34aee0ad4eb900a7ef5f566531125f42ec53f1bec5131bc484811790df1
Signature Algorithm – Java
private static final String ALGORITHM = "HmacSHA256";
public static String getSignature(String value, String key) {
try {
// Get an hmac_sha256 key from the raw key bytes
byte[] keyBytes = key.getBytes();
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, ALGORITHM);
// Get an hmac_sha256 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance(ALGORITHM);
mac.init(signingKey);
// Compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(value.getBytes()); // Convert raw bytes to Hex
byte[] hexBytes = new Hex().encode(rawHmac); // Covert array of Hex bytes to a String
return new String(hexBytes, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Signature Algorithm – C#
private static string GenerateSignature(string value, string key) { try { var enc = Encoding.UTF8; HMACSHA256 hmac = new HMACSHA256(enc.GetBytes(key)); hmac.Initialize(); byte[] buffer = enc.GetBytes(value); return BitConverter.ToString(hmac.ComputeHash(buffer)).Replace("-", "").ToLower(); } catch (Exception ex) { throw new Exception(ex.Message); } }