- Client ID and Key Pair
- Access Token
- Refresh Token
- Decryption
Authentication leverages public-key cryptography. In order to access the Aplos API, you must have a valid client id and a private key.
Should you choose to implement your own flow, or if you just want to know more about what goes on behind the scenes, we’ll walk through the basics of authenticating with Aplos.
Flow:
- Request an access token
- Decrypt the access token using your private key
- Make requests, always including the access token parameter
- Request a new access token whenever your token expires
Client ID and Key Pair
To obtain a client id, you must have an Aplos account and a user with administrative permissions.
Assuming you have these, you can generate a client id and key pair from the settings page.
NOTE: The client id used throughout this documentation, a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6 is for illustration purposes only.
Access to the Aplos API requires a valid client id.
Access Token
Expiration Time: 30 minutes
HTTP Method: GET
URL: https://app.aplos.com/hermes/api/v1/auth/:clientId
Parameters:
- [NONE]
When you want to use the API, you will need a valid access token. To obtain a new access token, you must retrieve one using the auth URL.
Example: https://app.aplos.com/hermes/api/v1/auth/a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6
The clientId is used to identify your account. This tells the API service not only which account is requesting access but also which public key must be used to generate the access token.*
* An access token is generated, linked to the requested account, and the token is encrypted using the respective public key. This ensures only the holder of the private key can decrypt the token and gain access to this account’s data via the API.
For more information on decrypting tokens, see the decryption section below.
An auth response will look something like this:
{
"version": "v2_0_0",
"status": 200,
"data": {
"expires": "2015-12-31T23:59:59.000-0700",
"token": "DgSAfTJppyiY3riXi7OF9LkdCVsdYV61biV6YawS9AKJAmfGLXfK3N00 ... OlJHM5gFCKAJKW3p1JzVA=="
}
}
Once you have an access token (decrypted), it MUST be provided with each request to the service. Failure to include the access token or using an invalid token will result in a 401 response (see Error Handling for details).
Access tokens expire 30 minutes after they are issued.
Refresh Token
Expiration Time: 30 minutes
HTTP Method: GET
URL: https://app.aplos.com/hermes/api/v1/auth/:clientId
Parameters:
- [NONE]
Access tokens expire 30 minutes after they are issued.
You may request a new token at any time using the auth URL.*
* Should this service be abused, your account may be deactivated. You should only require a new token once every 30 minutes.
Should you attempt to access the API using an expired token, the service response will look something like this:
{
"version": "v2_0_0",
"status": 401,
"exception": {
"message": "Token expired.",
"code": 1004
}
}
An HTTP status of 401 and an exception code of 1004 indicates an expired token (see Error Handling for details).
Decryption
In order to use a token from the service, you must decrypt it using your private key.
Steps to Decrypt a Token Using a Private Key File
- Download an encrypted token using the “auth” URL
- Decode the token
- Load and decode your private key
- Decrypt the token using the private key
Java Example
The following is a sample in Java.
package com.aplos.hermes.client.examples;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import com.menlolabs.gear.util.Functions;
public class DecryptToken {
/**
* Decrypt a token using a private key file
* @param encryptedToken
* @param privateKey
* @return Token decrypted using the given private key file
* @throws IOException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public String decryptToken(String encryptedToken, File privateKeyFile) throws IOException, NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException {
String privateKey = readTextFile(privateKeyFile);
byte[] key = fromBase64(privateKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key);
PrivateKey k = kf.generatePrivate(spec);
final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, k);
byte[] decryptedBytes = cipher.doFinal(fromBase64(encryptedToken));
return new String(decryptedBytes, "UTF-8");
}
/**
* Decode the given string using a Base64 decoder
* @param encoded
* @return Byte array decoded from the given base64 string
* @throws IOException
*/
private byte[] fromBase64(String encoded) throws IOException {
/*
* We are using an Aplos class here. Other options are Apache Commons and Java 8 Base64.
*/
return Functions.fromBase64(encoded);
}
/**
* Reads the file specified, returning the text as a String.
* @param is the stream to read
* @return String representation of the file data
* @throws IOException if an error occurs while reading.
*/
public static String readTextFile(File f) throws IOException {
FileInputStream is = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
is = new FileInputStream(f);
int l_numRead = 0;
byte[] buffer = new byte[32768];
while ((l_numRead = is.read(buffer)) != -1) {
bos.write(buffer, 0, l_numRead);
}
bos.flush();
bos.close();
is.close();
} finally {
is.close();
}
return bos.toString("UTF-8");
}
}