Authentication

Overview

At the core of using Wyre to build your next awesome app is knowing how to organize your authentication/authorization schemas to securely deliver API payloads. There are several ways to do this and what may be the best choice for you depends on a number of factors. Some of these may be your particular type of integration and the question of if you want to create a centralized authentication approach versus a decentralized approach. Let's dive in.

Centralized Authentication

The standard centralized authorization approach is used when you execute an API request directly to Wyre from a system under your control and its the most common approach. The safety of managed funds depends on the safety of your API credentials (you wouldn't distribute these credentials to customer devices, for example). Wyre provides for different authentication types if you prefer to go the standard route and they include.

📘

If you are using the accounts API to manage accounts for other people, you will need to use masquerading to control access.

Secret Key Signature Authentication

Wyre's Secret Key Signature Authentication simply involves using an API to perform a signature of the request you're attempting to make. This table describes the headers you'll need to supply when performing your request.

HTTP Header

Description

X-Api-Key

Your Wyre API key. Your key can be found at https://dash.sendwyre.com/settings/api-keys

X-Api-Signature

A signature used to verify the request was sent by the account holder. See Calculating the request signature.

We also consider it important that you include a GET parameter named timestamp which is the current time in millisecond epoch format. Wyre uses this timestamp for your security and to help protect against replay attacks.

Let's step into an understanding of how we ensure the request signature is calculated securely.

Calculating the request signature

Calculating the X-Api-Signature field is a two-step process:

  1. Concatenate the request URL with the body of the HTTP request (encoded using UTF8) into a string. Use an empty string for the HTTP body in GET requests
  2. Compute the signature as a HEX encoded HMAC with SHA-256 and your API Secret Key

📘

You must send the request body exactly as you sign it, whitespace and all. The server calculates the signature based on exactly what's in the request body.

const CryptoJS = require('crypto-js');
const YOUR_SECRET_KEY = SK-XXXX-XXXX-XXXX;

const signature = (url, data) => {
    const dataToBeSigned = url + data;
    const token = CryptoJS.enc.Hex.stringify(CryptoJS.HmacSHA256(dataToBeSigned.toString(CryptoJS.enc.Utf8), YOUR_SECRET_KEY));
    return token;
}

Signature example for when the data is a buffer

const CryptoJS = require('crypto-js');
const YOUR_WYRE_SECRET_KEY = SK-XXXX-XXXX-XXXX;
// Signature Calculation using Crypto-js
// url is a string, data is a buffer
const signature = (url, data) => {
    const urlBuffer = Buffer.from(url);
    const dataToBeSigned = Buffer.concat([urlBuffer, data]);
    const token = CryptoJS.enc.Hex.stringify(CryptoJS.HmacSHA256(dataToBeSigned, YOUR_WYRE_SECRET_KEY));
    return token;
}

📘

Code Examples

Looking for more detailed code examples for signature authentication?

Authorization Bearer

It is also possible to make authenticated requests using the Authorization header with a bearer token. The token is your Wyre secret key SK-XXXXX-XXXXX-XXXXX. The signature authentication is a bit more secure because your secret key is only encrypted via SSL in this case.

curl -X POST \
  https://api.testwyre.com/v3/orders/reserve \
  -H 'Authorization: Bearer SK-XXXX-XXXX-XXXX-XXXX' \
  -H 'Content-Type: application/json' \
  -H 'cache-control: no-cache' \
  -d '{
      "referrerAccountId": "AC_XXXXXXXXXXX"
}'

Decentralized Authentication

If your architecture plan requires centralized authentication but you'd like to explore your options? Great, because this is where you need to be.

For this mechanism, a client-generated bearer token is presented to the server on every request. This is a long, random string that acts as a long-lived session token, granting its bearer access. First, submit the key to the auth endpoint to initialize the key. This ensures its validity for subsequent use. But first, let's generate a secret key.

1. Generate the Secret Key

function makeSecret(length) {
    var result           = '';
    var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var charactersLength = characters.length;
    for ( var i = 0; i < length; i++ ) {
       result += characters.charAt(Math.floor(Math.random() * charactersLength));
    }
    return result;
 }

let secretKey = JSON.stringify({"secretKey": makeSecret(30)});

2. POST the Secret Key

POST /v2/sessions/auth/key?secretKey=X

See the endpoint reference for more details. Be very certain to use a cryptographically secure random number generator when creating this key, unless you know what you're doing. Remember that seeding it from (or hashing) any predictable source binds the token's security to the secrecy of the source.

The response contains an API Key that corresponds to the newly created credentials. This is helpful for managing the newly formed device connection (e.g. disconnecting the key from the account later, if necessary). The newly created session is valid, but has no corresponding account created.

This process is also explained here.

HTTP Header

Description

Authorization

The bearer token aka secret key. Make sure to include the string Bearer (followed by a space) before the secret token:

Bearer XXX

(replacing XXX with the secret key)

Next Steps

The first request after completing the auth token submission will typically be creating a new account. Make sure you supply the submitted bearer token when you hit this endpoint. After the account is created, the bearer token will now be associated with it. The rest of the API will now be available to it (and attempting account creation again with it will fail).

📘

Presently, tokens can also be used as the secret key for secret key signature auth requests. This provides slightly more security, as the token itself is not transmitted again after the initial transmission to you. You'll need to use the API key returned from the POST /v2/sessions/auth/key call for this.

Whitelisting IPs for Bearer Tokens

In order to whitelist IPs for bearer tokens (bring your own API key per child account):

  • Create the API key via Submit Auth Token.
  • Then you can follow up with v2/sessions/apiKey/:apiKeyId/ipWhitelist to assign the whitelist for that particular key.

Masquerading

This URL parameter allows your master account to query and transact on behalf of Sub-Accounts and Users.

If you are using the accounts or users APIs to manage balances and/or KYC data on behalf of the actual account holders (i.e. subaccounts or users) you'll use your own Wyre account credentials and then supply the query parameter masqueradeAs. This will cause the request to be performed on behalf of a specified person. This helps to safeguard against both accidental and malicious access abuse.

Unlike most API parameters, the masqueradeAs header must be passed as a query parameter in the API. If you are using API key signature auth, be sure to include this while signing.

For example, in order to get the account information for an account that you created with the ID AC-XXXXXXX, perform the following GET request:

GET https://api.sendwyre.com/v3/accounts/AC_XXXXXX1?masqueradeAs=AC_XXXXXX1

and

GET https://api.sendwyre.com/v3/users/US_XXXXXX1?masqueradeAs=user:US_XXXXXX1

(along with your own credentials, whichever scheme you are using)

Both accounts (AC-XXXXXXX) and users (US-XXXXXXX) slots in the URLs above are the same. They should be the child account or user you are trying to masquerade as. The way we determine the parent account is through the API/Secret keys associated with the parent account.

MasqueradeAs defaults to account SRN's. If it is not specified as a full SRN it will default to an account. For example, to masquerade the request as a user it must be user:US_AAAAAAAA, and not US_AAAAAAAA.