Authentication Guide
Introduction
In order to have access to our web services, each integrator receives a set of unique credentials. The credentials consist of a JSON Web Key (JWK), a Client ID, and an Entity ID. You will receive a set of demo store credentials at the beginning of your integration that are for your demo merchant. If you did not receive these, please reach out to your Implementation Coordinator. These credentials will only be valid for your demo merchant. At the completion of the API certification process, you will be provided a new set of credentials for production. You will need to use these credentials, as well as the other values described below, to generate a bearer token that can be used to authenticate all API requests. See the table below for definitions.
| NAME | DESCRIPTION |
|---|---|
| entity_id | The Entity ID is a unique identifier that is systematically generated when the merchant is installed on the EPS system. It is also referred to as the Merchant ID or MID. |
| client_id | A unique user ID systematically generated by EPS upon creating a new JWK for an organization. The Client ID can be unique to each individual merchant, or a main Client ID can be assigned at the reseller/owner level. |
| issuer_url | The URL where the token is being issued and is a static value. The value should be: https://smartpay.profitstars.com/auth |
| client_assertion | The signed JWK that you will generate for authentication to the issuer URL. See below for details on generating the client assertion. |
| grant_type | The type of credentials being granted. The value should be: client_credentials. |
| client_assertion_type | This identifies the type of client assertion being used. The value should be: urn:ietf:params:oauth:client-assertion-type:jwt-bearer |
| encoded_jwk | A cryptographically encoded JSON Web Key. This key will be supplied to you by the EPS Tech Integrations team, if you do not already have one. The key is used in generating your client assertion. |
Generating the Client Assertion
A client assertion should be generated using the following values: client_id, issuer_url, and encoded_jwk. This client assertion is used to request the access token for authentication to the API.
See below for an example of generating a client assertion using JavaScript. For examples of generating a client assertion using .NET, click this link.
Once the client assertion has been generated, proceed to request the access token by following the next steps below.
Example Client Assertion Creation:
//declare variables
const issuer_url = "https://smartpay.profitstars.com/auth";
const client_id = "your client id here";
const encoded_jwk = "your base64 encoded jwk string here";
// Decode the Base64 string
let jwk_json = atob(encoded_jwk);
const jwk = JSON.parse(jwk_json);
jwk.key_ops[0] = "sign";
// Helper: base64url decode/encode
function base64UrlEncode(buf) {
return Buffer.from(buf)
.toString('base64')
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
}
// Helper: base64url decode to Buffer
function base64UrlToBuffer(str) {
str = str.replace(/-/g, '+').replace(/_/g, '/');
while (str.length % 4) str += '=';
return Buffer.from(str, 'base64');
}
// Helper: Import JWK to CryptoKey (WebCrypto API)
async function importJwkToCryptoKey(jwk) {
return await crypto.subtle.importKey(
"jwk",
jwk,
{
name: "RSASSA-PKCS1-v1_5",
hash: { name: "SHA-256" }
},
false,
["sign"]
);
}
// Helper: Sign JWT
async function signJwt(header, payload, jwk) {
const encoder = new TextEncoder();
const headerB64 = base64UrlEncode(encoder.encode(JSON.stringify(header)));
const payloadB64 = base64UrlEncode(encoder.encode(JSON.stringify(payload)));
const unsignedToken = `${headerB64}.${payloadB64}`;
const key = await importJwkToCryptoKey(jwk);
const signature = await crypto.subtle.sign(
{ name: "RSASSA-PKCS1-v1_5" },
key,
encoder.encode(unsignedToken)
);
const signatureB64 = base64UrlEncode(signature);
return `${unsignedToken}.${signatureB64}`;
}
// JWT claims
const now = Math.floor(Date.now() / 1000);
const exp = now + 60;
const claims = {
sub: client_id,
jti: pm.variables.replaceIn('{{$guid}}'),
iat: now,
nbf: now,
exp: exp,
iss: client_id,
aud: issuer_url
};
// JWT header
const header = {
alg: "RS256",
typ: "client-authentication+jwt"
};
if (jwk.kid) header.kid = jwk.kid;
// Sign JWT
const jwt = await signJwt(header, claims, jwk);
Requesting Access Token
Once you have generated your client assertion, you can request an access token by submitting an HTML form via an HTTP POST command to the token request URL: https://smartpay.profitstars.com/auth/connect/token. See the table below for a list of the key value pairs that need to be submitted via HTML form to the authentication endpoint.
| KEY | VALUE |
|---|---|
| entity_id | Put your Entity ID here. |
| client_id | Put your Client ID here. |
| client_assertion | Put your generated client assertion here. |
| grant_type | client_credentials |
| client_assertion_type | urn:ietf:params:oauth:client-assertion-type:jwt-bearer |
Get Access Token Request Example
Header:
- "Method": POST
- "Endpoint":
https://smartpay.profitstars.com/auth/connect/token - Content-Type: application/x-www-form-urlencoded
Body:
- grant_type:client_credentials
- scope:apiaccess
- client_assertion_type:urn:ietf:params:oauth:client-assertion-type:jwt-bearer
- client_assertion:your client_assertion here
- client_id:your client_id here
- entity_id:your entity_id here
Using Access Token
Once you have been provided an access token by the RequestAccessToken response, you will put the access token in the security header of each web service request to authenticate each request. The token lasts 15 minutes before expiring. After it expires, you will need to send a new request to the token endpoint for a new authentication token. See below for an example request with the security token:
Example Web Service Request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pv="https://ssl.selectpayment.com/PV">
<soapenv:Header>
<pv:SecurityHeader>
<pv:BinarySecurityToken>your security token here</pv:BinarySecurityToken>
</pv:SecurityHeader>
</soapenv:Header>
<soapenv:Body>
<pv:GetTransaction>
<pv:storeId>0</pv:storeId>
<pv:storeKey isNull="true" />
<pv:entityId>12345</pv:entityId>
<pv:transactionReferenceNumber>your transaction number here</pv:transactionReferenceNumber>
</pv:GetTransaction>
</soapenv:Body>
</soapenv:Envelope>
Handling Errors
- Invalid Client Error This error can appear for a couple of reasons: Either your client_id or entity_id are incorrect. To resolve this error, correct the entity_id and/or client_id that you provided.
{
"error": "invalid_client"
}
- Unauthorized Client Error This error indicates that the client you are trying to request a token for is not authorized for the token request endpoint. First, confirm that you are using the correct entity_id and client_id. If the entity_id/client_id are correct, you may not have authorization for the entity that you are trying to connect to. You can contact EPS Support to request that the entity you are trying to connect to is authorized for the authentication service.
{
"error": "unauthorized_client"
}
- Invalid Scope Error This means that your scope is invalid. The scope should be "apiaccess".
{
"error": "invalid_scope"
}
- Invalid Request Error This means that your HTTP request type is not valid. The token request endpoint only accepts HTTP POST request.
{
"error": "invalid_request"
}
- Unsupported Grant Type Error This means that your grant_type is not valid. The grant_type should be "client_credentials".
{
"error": "unsupported_grant_type"
}
Next Steps
If the process was successful, you are ready to move on and work with some of our other guides. If you were unable to proceed after troubleshooting, we will work with you to find a solution. We are here to help you get up and running, so reach out to us.
- Explore our payment guides - We have custom-built guides to show how to leverage our APIs in common use case scenarios. If your situation or question is not covered in the current guide, consult the list to find a resource that fits your business needs.
- Review the API Reference - While our guides are a great starting point, the API Reference provides the full details for all our available APIs and their technical specifications.