Skip to main content

Welcome to eMoney Access! eMoney APIs enable you to connect with eMoney and build data connections to tightly integrate your user experience.

This overview details the process of gaining API access and the initial API connection. We do this using examples and available online resources as a great place to start and assist.

If you are interested in connecting to eMoney Access APIs, please use the Contact Us link below. Current eMoney subscribers can also contact Client Services or Sales directly for assistance.

We provide access to eMoney APIs by using a JSON Web Token (JWT), here is a quick introduction to JWT, and X.509certificate.

When you first start using eMoney Access, you will connect to our Test region. This is where you will become familiar with our APIs and start coding against realistic data scenarios. The steps for connecting to Test and Production are the same but different urls are needed. Both will be provided throughout these instructions.

Setting up Access to the eMoney Access API

An eMoney representative will work with you to complete the set-up of your firm's API access and provide an API Key. As part of this process you will need to:

  1. Acquire two X.509 certificates with valid signing chains, one for Test and one for Production. Certificate requirements are outlined at the bottom of this page.
  2. Send the two X.509 public certificates to your eMoney representative. Note which certificate corresponds to which environment. A member of the eMoney team will upload this certificate which is used for authentication. Do not send the private key or include your private key when sending the certificate.
  3. Your eMoney representative will provide two Client IDs, one for Test and one for Production, as well as a single API key.
    1. The Client ID and certificate pair authorizes you to request bearer tokens for your office and is only needed when retrieving a bearer token.
    2. The API key identifies you as the caller when making API calls to the eMoney API system and is required on every API request.

Once you have the Client ID and the API key provided by an eMoney representative, you can begin to make requests.  
 

Authentication

To authenticate you must generate a Client Assertion JWT and send this information using a POST request to the signin service’s token endpoint. This should be done via your programming language of choice. We provide examples in C# and JavaScript at the bottom of this page.

Step One: Generate a JWT

Generate a Client Assertion JSON Web Token (JWT) using the Client ID and your private key file (*.pfx).

     Test: https://signin-externalbeta2.emaplan.com/connect/token  
     Production: https://signin.emaplan.com/connect/token

A signed JWT consists of 3 parts: the header, payload, and signature.

Header

  • Algorithm is "RS256".
  • Token Type is "JWT".

Payload

  • Submitter is your eMoney API Client ID
  • Assertion Issue is also your eMoney API Client ID
  • Assertion Expiration is an epoch time stamp you choose. The timestamp may be up to a day into the future. Once this timestamp is in the past, the signin Server will no longer accept the JWT assertion, and a new one must be generated. This gives you flexibility in how often you need to create a new JWT assertion.  Many people choose to generate a new JWT assertion each time they request a new bearer token.
  • Audience is the eMoney signin server token endpoint URL.

Signature

The signature is the signing secret from the private key of the test x509 signing certificate registered with eMoney for API usage. To create the signature, take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.

Examples of the Header and Payload are provided at the bottom of this page in the “JWT Sample” section. You can also find examples of the different options for generating a JWT.

Step Two: Send the JWT to eMoney's server

The JWT must be sent to the OAuth server as form data that has been encoded into the URL parameter. On successful generation of your Client Assertion, you now need to POST this to the OAuth server to receive the Access Token. This access token will be used to make all API calls.

The HTTP POST request body must be in the form-urlencoded format and have the Content-Type header set to application/x-www-form-urlencoded. The body will have the parameters shown in the sample at the bottom of this page. Please note that the URLs are considered case sensitive.

Generate an access token by sending a POST request to authenticate against this endpoint.

     Test: https://signin-externalbeta2.emaplan.com/connect/token  
     Production: https://signin.emaplan.com/connect/token

In the body of the request, select x-www-form-urlencoded to be able to enter key/value pairs for the request body.

  • grant_type is "client_credentials"
  • client_assertion_type is "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
  • client_assertion is "{yourClientAssertionJWT}"
  • scope is "API" for access to all data, or a set of scopes such as “platform:clients:planning:projection platform:clients:planning:read”. Note that eMoney Planning Components require you to specify specific platform scopes when requesting the token. The global “API” scope will not work for components. See the documentation for each individual component to see what scopes are required.
x-www-form-urlencoded request example

After successfully posting to the OAuth server, you will receive a response that will include your access token.  You will use this token to make requests to the eMoney API endpoints.

The success response will look like this:

access token successful response example

If your JWT passed as client_assertion in the token request is invalid, you will receive an "invalid_client" response value like this:

invalid token response example

Sending Requests to the eMoney Access APIs

All requests must include a 'Bearer Token' containing the token value retrieved from the eMoney Authentication Server. Use the access token as a Bearer Authorization header for your request.  

Bearer Authorization header example

All requests must also contain a header key/value pair containing the API key provided to you by eMoney.

Please refer to this sample header:

Sample header example

Send the API request to the eMoney Access API.  Review the Swagger documentation for the success and error responses for any of our APIs.

     Test: https://api-externalbeta2.emaplan.com/  
     Production: https://api.emoneyadvisor.com/

Certificate Requirements

The API certificates must be signed by an external, trusted Certificate Authority (CA).

  • Wildcard certificates are not accepted
  • All certificates must be valid for 2 years or less
  • Must use SHA256 or stronger hashing algorithm.

An EV certificate, although preferred, is not a requirement. Standard certificates are acceptable if they satisfy the above. Certificate options will vary by provider.

The eMoney Security Team has identified the following acceptable CAs:

  • Globalsign
  • Godaddy
  • Symantec
  • Verasign
  • Digicert
  • Cetum
  • Geotrust
  • Comodo
JWT Sample

Sample JWT Request

{

   "grant_type": "client_credentials", 
   "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", 
   "client_assertion": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjQ1MzU5MUU2MTFGREVF....................................", 
   "scope": "API"

}

Header

The header includes information about the key and algorithm used to sign the payload like below. The alg and typ are required. The kid is optional.

jwt header example

Payload

The associated payload should look like this. All fields are required. Using your Client ID provided by the eMoney team, replace the below tag {Client ID} with your Client ID. The Subject Claim (sub), Expiry (exp), Issuer (iss) and Audience (aud) are all required in the payload. The Audience claim should be the OAuth server token endpoint that you received from the eMoney team. You may choose to specify a userid claim, if you do the returned access token will be limited to the abilities and access level of that user. That user must be in your office or sub offices.

Tokens generated for eMoney Components must include this userid claim with a valid eMoney user/client UUID. This is for security reasons as the token will be used by front-end code running on your user’s browser and so is therefore accessible to them if they choose to inspect the page source. Tokens generated without the userid claim have access to all data in your office at an “admin” role level.

When generating tokens for eMoney Components we highly recommend you use the eMoney user/client UUID associated with the user currently logged in and viewing your system. Not following this recommendation would allow users of your system to access eMoney data they do not normally have access to.

For the same reason, to use eMoney Components we also require you to specify specific platform scopes when requesting the token and not the global “API” scope.  See the documentation for each individual component to see what scopes they need. The scope claim on the token passed into a component does not need to exactly match the scopes required by that component. The scope claim may contain more scopes than are needed by any individual component so that you can use the same token for all components on a single page, but we recommend you limit the requested scopes to only what is required by the components you are using. You may also request individual tokens for each component if you so choose.

JWT payload example

Signature

The signature is used to verify that the correct private key was used to sign the JWT assertion and that the JWT assertion was not modified after being signed.  Signing the JWT Assertion will vary depending on the programming language you are using.  JWT.io has pre-made libraries that can handle this process for you, written in a variety of languages.  Otherwise, see rfc7519 for the JWT specification.

Generating a JWT with an Online Tool
  1. Go to https://jwt.io
  2. Select 'RS256' as the algorithm
  3. One of the payload attributes of the Client Assertion is an expiration timestamp for the assertion itself.  For testing in a non-Production environment, we recommend you set this to expire 2 hours from current time (extended testing may require you re-generate a new JWT). Use public site https://www.epochconverter.com/ to get Epoch time stamp. First select date and time till when the client assertion being generated will be valid and then click the button 'Human date to Timestamp' to get it.  
  4. Update the payload with the following info:
     {
       "sub": "{APIClientID}",
       
    "exp": {Epochtimestampexpiration},
       
    "iss": "{APIClientID}", 
       "aud": "{eMoneyAuthServerTokenRequestEndpointURL}"
    }

    An example of this would be:
     {
       "sub": "87c5fe3b53b44ee1aae0daf6d055dbcd",
       "exp": 1560350834,
       "iss": "87c5fe3b53b44ee1aae0daf6d055dbcd",
       "aud": "https://signin-externalbeta2.emaplan.com/connect/token"
    }
  5. Copy the private key extracted from the private certificate (key.pem if you generated the certificate per above instructions) and paste into the 'PRIVATE KEY' text area in the jwt.io debugger Signature area. The private will be the content beginning with the line '-----BEGIN PRIVATE KEY-----' and ending with the line '-----END PRIVATE KEY-----' including the content in between.  If there is any issue in the paste, the token will not be generated. 

    You can verify the signature by pasting the PRIVATE key into the 'Public' key form field in jwt.io to see the "Signature Verified" confirmation beneath the Debugger. Note that while jwt.io performs all encoding and debugging locally within the browser, please do not use this utility with certificates meant for production use with eMoney.
  6. The Base64 'Encoded' output of the jwt.io debugger (or via your own local code option below) is your JWT and what you will use in the eMoney token request as your Client Assertion
jwt postman example
Generating a JWT using Local code

If you are familiar with JWT and have a local development environment, you can generate the JWT using eMoney inputs provided and by connecting to your certificate store. 

C# Example

using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Net.Http;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
 
namespace eMoneyAPITestTool
{
    public class eMoneyAuthorization
    {      
        public string GetClientAssertionToken(string clientId, X509Certificate2 certificate, string tokenEndpoint)
        {
            SecurityToken st = null;
            SecurityTokenHandler sth = null;
            SecurityTokenDescriptor std = null;
 
            sth = new JwtSecurityTokenHandler { SetDefaultTimesOnTokenCreation = false };
            std = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[] { new Claim(JwtRegisteredClaimNames.Sub, clientId) }),
                SigningCredentials = new SigningCredentials(new X509SecurityKey(certificate), SecurityAlgorithms.RsaSha256Signature),
                Audience = tokenEndpoint,
                Expires = DateTime.UtcNow.AddMinutes(600), //for 10 hrs
                Issuer = clientId
            };
            st = sth.CreateToken(std);
 
            return sth.WriteToken(st);
        }
 
        public eMoneyAuthInfo GetAccessToken(string certName, string api_clientId, string authTokenURL)
        {
            eMoneyAuthInfo info = new eMoneyAuthInfo();
            X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
 
            store.Open(OpenFlags.ReadOnly);
            X509Certificate selectedCertificate = null;
 
            foreach (X509Certificate cert in store.Certificates)
            {
                if (cert.Subject.Contains(certName))
                {
                    selectedCertificate = cert;
                    break;
                }
            }
 
            try
            {
                info.ClientAssertion = new eMoneyAuthorization().GetClientAssertionToken(api_clientId, (X509Certificate2)selectedCertificate, authTokenURL);
                var requestContent = new FormUrlEncodedContent(new Dictionary<string, string>
                {
                    { "grant_type", "client_credentials" },
                    { "client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" },
                    { "client_assertion", info.ClientAssertion },
                    { "scope", "API" }
                });
                 
                using (var client = new HttpClient())
                {
                    client.BaseAddress = new Uri(authTokenURL);
                    client.DefaultRequestHeaders.Clear();
 
                    HttpResponseMessage response = client.PostAsync(authTokenURL, requestContent).Result;
 
                    if (response.IsSuccessStatusCode)
                    {
                        string callResponse = response.Content.ReadAsStringAsync().Result;
                        eMoneyAccessToken x = Newtonsoft.Json.JsonConvert.DeserializeObject<eMoneyAccessToken>(callResponse);
                        if (x != null)
                        {
                            info.BearerToken = x;
                        }
                    }
                }
                return info;
            }
            catch (Exception e)
            {
                throw new Exception("Error occurred in getting an Access Token.\r\n" + e.ToString());
            }
        }
 
        public T SimpleGETRequest<T>(string endpointURL, string accessToken)
        {
            object result = new object();
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(endpointURL);
                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
                client.DefaultRequestHeaders.Add("apikey", "**** consumerKey goes here ****");
 
                HttpResponseMessage response = client.GetAsync(endpointURL).Result;
 
                if (response.IsSuccessStatusCode)
                {
                    string callResponse = response.Content.ReadAsStringAsync().Result;
                    result = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(callResponse);
                }
            }
            return (T)Convert.ChangeType(result, typeof(T)); ;
        }
    }
    public class eMoneyAccessToken
    {
        public string access_token { get; set; }
        public string token_type { get; set; }
        public long expires_in { get; set; }
    }
 
    public class eMoneyAuthInfo
    {
        public string ClientAssertion { get; set; }
        public eMoneyAccessToken BearerToken { get; set; }
    }
}

Javascript Example

import axios from 'axios';
import { sign } from 'jsonwebtoken'; // https://www.npmjs.com/package/jsonwebtoken
import { stringify } from 'querystring';
import { exec } from 'child_process';

// Get an access token from the Authentication server
const getAuthorization = async () => {
  const config = {
    headers : {
    'Content-Type': 'application/x-www-form-urlencoded'
    }
  }
  const payload = {
    "grant_type": "client_credentials",
    "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
    "client_assertion": createClientAssertionJWT(),
    "scope": "API",
  }
  const url = `${this.authUrl}/connect/token`
  return axios.post(url, stringify(payload), config)
    .then((response) => {
      return response.data.access_token;
    })
    .catch(e => {
      throw 'Failed to get token'
    })
}
// Craft the JWT according to the specs from the Auth document
const createClientAssertionJWT = () => {
  const certThumbprint = getSHA1Fingerprint(this.publicCert)
  const header = {
    algorithm: "RS256",
    kid: certThumbprint,
    typ: "JWT"
  }
  const payload = {
    sub: this.clientId,
    exp: Math.trunc(Date.now() / 1000) + 600,
    iss: this.clientId,
    aud: this.authUrl + '/connect/token'
  }
  // Necessary since we pass in the private cert from an ENV var
  const cert = this.privateCert.replace("\\n", "\n");
  const jwt = sign(payload, cert, { header, algorithm: 'RS256' })
  return jwt
}
// We use openssl to create the fingerprint for the public cert.
// This function can be avoided by generating the fingerprint manually and adding it
// but requires another step when the public and private certs need to be updated.
const getSHA1Fingerprint = async (cert: string) => {
  let publicCert = cert
  let fingerprint: string
  publicCert = publicCert.replace("\\n", "\n");
  exec(`touch publicCert.crt && echo "${publicCert}" >> publicCert.crt`)
  exec('openssl x509 -noout -fingerprint -sha1 -inform pem -in publicCert.crt', (err, stdout, _stderr) => {
    if (err) {
      console.log(err)
      return
    }
    fingerprint = stdout
    if (fingerprint && fingerprint.includes('SHA1 Fingerprint=')) {
      fingerprint = fingerprint.replace('SHA1 Fingerprint=', '').replace(/:/g, '').replace('\n', '')
      return fingerprint
    } else {
      return null
    }
  })
}

 

Successful Responses

Sample Successful Response

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
   "access_token":"2YotnFZFEjr1zCsicMWpAA",
   "token_type":"Bearer",
   "id_token": "9dfjak398djfkgjh",
   "expires_in":3600
}

Possible Success Response Parameters

Parameter Parameter Required
access_token OAuth 2.0 Access Token. This is returned unless the response_type value used is id_token. OAuth 2.0 Access Token. This is returned unless the response_type value used is id_token.
token_type OAuth 2.0 Token Type value. The value MUST be Bearer or another token_type value that the Client has negotiated with the Authorization Server. Clients implementing this profile MUST support the OAuth 2.0 Bearer Token Usage [RFC6750] specification. This profile only describes the use of bearer tokens. This is returned in the same cases as access_token is. Yes
id_token ID Token Yes
state OAuth 2.0 state value. REQUIRED if the state parameter is present in the Authorization Request. Clients MUST verify that the state value is equal to the value of state parameter in the Authorization Request. Conditionally
expires_in Expiration time of the Access Token in seconds since the response was generated. No
Error Responses

Sample Error Response

HTTP/1.1 400 Bad Request
   Content-Type: application/json
   Cache-Control: no-store
   Pragma: no-cache
   {
      "error": "invalid_request"
   }

 

Possible Error Response Parameters

Parameter Parameter Required
error Error code Yes
error_description Human-readable ASCII encoded text description of the error. No
error_uri URI of a web page that includes additional information about the error. No
state OAuth 2.0 state value. REQUIRED if the Authorization Request included the state parameter. Set to the value received from the Client Conditionally

 

Possible Error Codes that can be returned in the "error" parameter from the response

Error Description
invalid_request The request is missing a required parameter, includes an unsupported parameter value (other than grant type), repeats a parameter, includes multiple credentials, utilizes more than one mechanism for authenticating the client, or is otherwise malformed.
invalid_client Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The authorization server MAY return an HTTP 401 (Unauthorized) status code to indicate which HTTP authentication schemes are supported. If the client attempted to authenticate via the "Authorization" request header field, the authorization server MUST respond with an HTTP 401 (Unauthorized) status code and include the "WWW-Authenticate" response header field matching the authentication scheme used by the client.
invalid_grant The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client
unauthorized_client The authenticated client is not authorized to use this authorization grant type.
unsupported_grant_type The authenticated client is not authorized to use this authorization grant type.