Authentication
All API calls to Freemarket are authenticated using JWT authentication tokens according to the OpenID Connect standard,
OAuth 2.0 Password Grant.
Authentication consists of two independent parts, the authentication of the client (the piece of software integrating with the API) and the authentication of the service user account to establish the security context (permissions).
The authentication token can be obtained by either using the client secret or using a client certificate and the mutual TLS protocol.
Client secret authentication endpoint
This endpoint accepts a client id and secret combination to authenticate the client.
POST /connect/token HTTP/1.1
Host: identity.wearefreemarket.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&scope=freemarketFXAPI&client_id={clientId}&client_secret={clientSecret}&username={userEmail}&password={userPassword}
curl --request POST 'https://identity.wearefreemarket.com/connect/token'
--header 'Content-Type: application/x-www-form-urlencoded'
--data-urlencode 'grant_type=password'
--data-urlencode 'scope=freemarketFXAPI'
--data-urlencode 'client_id={clientId}'
--data-urlencode 'client_secret={clientSecret}'
--data-urlencode 'username={userEmail}'
--data-urlencode 'password={userPassword}'
// request token
HttpClient client = // get HttpClient
var response = await client.PostAsync("https://localhost/connect/token", new FormUrlEncodedContent(new KeyValuePair<string, string>[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("scope", "freemarketFXAPI"),
new KeyValuePair<string, string>("client_id", clientId),
new KeyValuePair<string, string>("client_secret", clientSecret),
new KeyValuePair<string, string>("username", userEmail),
new KeyValuePair<string, string>("password", password)
}));
if (!response.IsSuccessStatusCode)
{
throw new Exception($"Unsuccessfull response: {response.StatusCode} - {response.ReasonPhrase}");
}
string responseContent = await response.Content.ReadAsStringAsync();
JsonDocument responseDocument = JsonDocument.Parse(responseContent);
string accessToken = responseDocument.RootElement.GetProperty("access_token").GetString();
int expiresInSeconds = responseDocument.RootElement.GetProperty("expires_in").GetInt32();
String enc = "UTF-8";
URL url = new URL("https://identity.wearefreemarket.com/connect/token");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
StringBuilder contentBuilder = new StringBuilder();
contentBuilder.append("grant_type=password&");
contentBuilder.append("scope=freemarketFXAPI&");
contentBuilder.append("client_id=").append(URLEncoder.encode(clientId, enc)).append("&");
contentBuilder.append("client_secret=").append(URLEncoder.encode(clientSecret, enc)).append("&");
contentBuilder.append("username=").append(URLEncoder.encode(userEmail, enc)).append("&");
contentBuilder.append("password=").append(URLEncoder.encode(userPassword, enc));
byte[] content = contentBuilder.toString().getBytes(enc);
conn.setRequestProperty("Content-Length", Integer.toString(content.length));
try (OutputStream outputStream = conn.getOutputStream()) {
outputStream.write(content);
}
int responseCode = conn.getResponseCode();
if (responseCode != 200) {
throw new Exception("Unsuccessfull response code: " + responseCode);
}
ObjectMapper mapper = new ObjectMapper();
try (Reader reader = new InputStreamReader(conn.getInputStream(), enc)) {
HashMap<String, Object> response = mapper.readValue(reader, new TypeReference<HashMap<String, Object>>() {});
System.out.println("access_token: " + response.get("access_token"));
System.out.println("expires_in: " + response.get("expires_in"));
System.out.println("token_type: " + response.get("token_type"));
System.out.println("scope: " + response.get("scope"));
}
$curl = curl_init();
$data = array(
'grant_type' => 'password',
'scope' => 'freemarketFXAPI',
'client_id' => '{clientId',
'client_secret' => '{clientSecret}',
'username' => '{userEmail}',
'password' => '{userPassword}
);
$this->setup_curl($curl, '/connect/token', array(), true, $data);
$result = curl_exec($curl);
if ($result === false) {
// error handling
}
curl_close($curl);
$decoded = json_decode($result);
// the access token
$accessToken = $decoded->access_token;
// the access token expiry in seconds
$expiry = intval($decoded->expires_in);
| parameter |
description |
| client_id |
the identifier of the integrating party, obtained upon request from your account manager |
| client_secret |
the password associated with the client_id |
| username |
the freemarket portal email address associated with the user account representing the integrating service |
| password |
the password associated with the user account |
Mutual TLS Client authentication endpoint
This endpoints accepts a client id and a client certificate.
Note
The client certificate can be self signed, only the key material and thumbprint is required.
POST /connect/mtls/token HTTP/1.1
Host: identity.wearefreemarket.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&scope=freemarketFXAPI&client_id={clientId}&username={userEmail}&password={userPassword}
curl --request POST 'https://identity.wearefreemarket.com/connect/mtls/token'
--header 'Content-Type: application/x-www-form-urlencoded'
--data-urlencode 'grant_type=password'
--data-urlencode 'scope=freemarketFXAPI'
--data-urlencode 'client_id={clientId}'
--data-urlencode 'username={userEmail}'
--data-urlencode 'password={userPassword}'
--key ./cert-key.pem
--cert ./cert.pem
// request token
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
Scope = "api1"
});
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return;
}
Console.WriteLine(tokenResponse.Json);
String enc = "UTF-8";
URL url = new URL("https://identity.wearefreemarket.com/connect/mtls/token");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
KeyStore keyStore = KeyStore.getInstance("PKCS12");
try (InputStream inputStream = new FileInputStream(certFile)) {
keyStore.load(inputStream, certPassword.toCharArray());
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
kmf.init(keyStore, certPassword.toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
StringBuilder contentBuilder = new StringBuilder();
contentBuilder.append("grant_type=password&");
contentBuilder.append("scope=freemarketFXAPI&");
contentBuilder.append("client_id=").append(URLEncoder.encode(clientId, enc)).append("&");
contentBuilder.append("username=").append(URLEncoder.encode(userEmail, enc)).append("&");
contentBuilder.append("password=").append(URLEncoder.encode(userPassword, enc));
byte[] content = contentBuilder.toString().getBytes(enc);
conn.setRequestProperty("Content-Length", Integer.toString(content.length));
try (OutputStream outputStream = conn.getOutputStream()) {
outputStream.write(content);
}
int responseCode = conn.getResponseCode();
if (responseCode != 200) {
throw new Exception("Unsuccessfull response code: " + responseCode);
}
ObjectMapper mapper = new ObjectMapper();
try (Reader reader = new InputStreamReader(conn.getInputStream(), enc)) {
HashMap<String, Object> response = mapper.readValue(reader, new TypeReference<HashMap<String, Object>>() {});
System.out.println("access_token: " + response.get("access_token"));
System.out.println("expires_in: " + response.get("expires_in"));
System.out.println("token_type: " + response.get("token_type"));
System.out.println("scope: " + response.get("scope"));
}
| parameter |
description |
| client_id |
the identifier of the integrating party, obtained upon request from your account manager |
| username |
the freemarket portal email address associated with the user account representing the integrating service |
| password |
the password associated with the user account |
Note
The mutual TLS endpoint no longer accepts a client secret.
Authentication token structure
A successful authentication request yields a response with a 200 status code and a standard JWT token in its body that looks like the following
{
"access_token": "eyJhbGciOi...[redacted]...Yv1egxCrAA",
"expires_in": 900,
"token_type": "Bearer",
"scope": "freemarketFXAPI"
}
| parameter |
description |
| access_token |
the encoded access token itself |
| expires_in |
the lifetime of the token, in seconds |
| token_type |
the type of token, always "Bearer" |
| scope |
the scope to which the token grants access |
The token needs to be passed verbatim in every request to the API in the Authorization header.
GET https://portal.wearefreemarket.com/api/v1/Accounts HTTP/1.1
Host: portal.wearefreemarket.com
Authorization: Bearer eyJhbGciOi...[redacted]...Yv1egxCrAA
Note
The lifetime of the token is 15 minutes.
In case of token expiry, the returned response will have a status code of 401 Unauthorized.
Token reuse within its lifetime is encouraged.
An unsuccessful authentication request returns a response with a 400 status code and a JSON encoded structure with a single property explaining the erorr
{
"error": "invalid_client"
}
| parameter |
description |
| error |
the authentication error message |
Among the possible errors are:
| error message |
problem description |
| invalid_client |
the client {clientId} does not exist, or the provided {clientSecret} is incorrect |
| invalid_user |
the {username} does not exist, or the provided {password} is incorrect |