Authentication¶
The Yocuda Receipt API offers two methods of authentication: bearer tokens and URL signatures.
Bearer tokens are recommended for machine to machine authentication, e.g. performing requests from a POS system. For convenience, Yocuda can issue long-lived tokens. Alternatively, the caller may issue short-lived tokens using a shared secret.
URL signatures, or more specifically, time limited HMAC-SHA256 signatures are also generated using a shared secret but don’t rely on the Authorization
header. This method is recommended for performing requests directly from end-user devices because it allows to tie the signature to specific consumers. See Generating Signatures on Behalf of Consumers for more details on this work-flow.
Bearer Tokens¶
Tokens issued by Yocuda may be used directly in requests:
POST /pos/data HTTP/1.1
Host: api.ereceipts.co.uk
Authorization: Bearer eyJhbGciOiJIUzI1NiIsImtpZCI6IkxGUlRNTEtIUU1VUTlXNklKRVBNIiwidHlwIjoiSldUIn0.eyJqdGkiOiI3NTE1MDc4My0yOTc0LTRkZmMtODk0Yy00ZWYyZjk1YWRkZGYifQ.r4kEkNDFwk29_LK05d5odtM35BJRlcc3RMVDEeGOuCc
Content-Type: application/json
Content-Length: ...
It’s essential to ensure confidentiality of tokens. If required, Yocuda can revoke any issued token.
To obtain a token please contact your Yocuda representative.
Token Generation¶
Bearer tokens are JSON Web Tokens with the following header and payload:
{
"alg": "HS256",
"kid": "...",
"typ": "JWT"
}
{
"exp": 1710365510,
"jti": "..."
}
The kid
and the shared secret required for signing tokens are provided by Yocuda. The exp claim controls token expiry and should be set on all generated tokens. The jti claim is optional but recommended - it should be set to a UUIDv4.
JSON Web Tokens implementations are widely available. For example, in Python using PyJWT:
import binascii
import datetime
import uuid
import jwt
kid = "LFRTMLKHQMUQ9W6IJEPM"
secret = binascii.a2b_base64("YeduWrjUyVcbDaHuV4mGn3r5PNdBbwUNhPHVuC6dE94=")
now = int(datetime.datetime.now(datetime.timezone.utc).timestamp())
exp = now + 300 # Expire the token in 5 minutes
jti = str(uuid.uuid4())
token = jwt.encode(
{"exp": exp, "jti": jti}, secret, algorithm="HS256", headers={"kid": kid}
)
It’s essential to ensure confidentiality of the shared secret and the issued tokens. If required, Yocuda can revoke tokens issued with a specific kid
.
To obtain a kid
and shared secret please contact your Yocuda representative.
URL Signatures¶
Back-ends that perform API requests must generate short-lived signatures that can be used to perform the requests. The life-time of the signature should be short enough that it has little value to somebody that might intercept the signature, but long enough that it doesn’t expire before the request has been made, which could include enough time for retrying the request. The maximum life-time of a signature is 24 hours.
Signature Generation¶
The signature used to authenticate requests is generated using the HMAC-SHA256 algorithm. The algorithm is applied to a message consisting of the key
, consumer
(optional), and expires
arguments that are present in the URL (see Requests below) in conjunction with the shared secret. Other arguments present in the query string do not affect the signature calculation.
For requests that do not use the consumer argument, the following pseudocode shows how to generate the signature:
expires="1637763396"
key="8IMF3WFX4Z11I8WTPL2P"
secret=base64_decode("O4x13cuK5T+lbd72NKd4D4dWFJaDkdim6gvdjLziQFY=")
signature=<urlencode(base64(hmac-sha256(
secret,
key + "\n" + expires
)))>
signature=<urlencode(base64(hmac-sha256(
base64_decode("D96dRi6Hd+n848TVbEAXi8iANGbe4MjgAA1A3ytCQu8="),
"8IMF3WFX4Z11I8WTPL2P\n1637763396"
)))>
signature="0cv%2BYkrN9CMBMnYELldaPOt7JZQAksAcsXt9G8hoFbM%3D"
When a signature should be tied to a specific consumer, the following pseudocode shows how to generate the signature:
expires="1637763396"
consumer="1001"
key="8IMF3WFX4Z11I8WTPL2P"
secret=base64_decode("O4x13cuK5T+lbd72NKd4D4dWFJaDkdim6gvdjLziQFY=")
signature=<urlencode(base64(hmac-sha256(
secret,
key + "\n" + consumer + "\n" + expires
)))>
signature=<urlencode(base64(hmac-sha256(
base64_decode("D96dRi6Hd+n848TVbEAXi8iANGbe4MjgAA1A3ytCQu8="),
"8IMF3WFX4Z11I8WTPL2P\1001\1637763396"
)))>
signature="m57MtdATa3zuSEKcK4FOaP0UGOQ7TQjD3KSFI8GeoAI%3D"
Runnable code examples for various language can be found on the Signature Example page.
Requests¶
Adding authentication to a request requires providing the following query string arguments (in addition to any other arguments required for the API resource being requested):
Key |
Description |
Example value |
---|---|---|
|
access key |
|
|
the (optional) consumer identifier; this is a vector parameter, which accepts multiple identifiers separated by commas |
|
|
the expiry time, expressed in whole seconds since the epoch (where the epoch is defined as: 00:00:00 UTC on 1 January 1970) |
|
|
the HMAC-SHA256 signature calculated as shown in the above pseudocode |
|
The Consumer Parameter¶
When generating signed URLs for an end-user, the URL should always include the identifier for that particular end-user in the consumer
parameter. In some cases a single consumer might have multiple identifiers, e.g. an email address and a phone number or multiple card numbers. In such cases it is possible to pass all the identifiers that identify that consumer in the consumer
parameter, separated by commas.
Error Conditions¶
If the signature is invalid a request will return a 403 Forbidden
status code and will provide an explanation of why the authentication failed
in the response.
It is important to ensure that the clock of the machine(s) that are generating signatures is correct and kept continuously up-to-date. If the clock drifts it is very probable that requests will be rejected by the Yocuda Receipt API.
Generating Signatures on Behalf of Consumers¶
Authentication of request to the API uses a shared-secret, HMAC based signature over a number of fields enabling an authentication server to hand out time-limited authentication signatures for use in applications on behalf of a single consumer.
Definitions:
API: the collection of HTTP resources provided by Yocuda, for which authentication may be required
Application: an application, such as a website or smartphone application, which needs to make requests on behalf of a consumer
Authenticating Server: a server which is able to authenticate a consumer and subsequently is able to produce signatures
Signature: a time-limited signature, created using an application specific key, a consumer identifier, a pre-shared secret and an expiration time, generated using the HMAC-SHA256 algorithm
Consumer Identifier: an identifier that is used to request a specific consumer’s receipts
Workflow¶
A typical workflow for using the API using the HMAC based signature would be as follows:
A user logs in using their application (a smartphone or on a website)
the application passes the username and password to the authenticating server which either refuses the login attempt or accepts the username and password combination
A user requests a view in the application which requires the use of the API, for example by viewing a list of their receipts
the application checks to see if it has any cached and non expired HMAC signatures, at this point it does not and
the application makes an request to the authentication server for an HMAC signature for use in subsequent requests to the API
the authentication server retrieves the following items of information: the pre-shared secret key, the access key, and the identifier used to fetch this users receipts, calculates an expiry time for this signature, and finally calculates the HMAC signature using the gathered information
the computed signature, the access key, the identifier, and the expiry time is returned to the application
the application uses the returned items to make a request to the API, processing the result and presenting it to the user
A user requests a view in the application which requires the use of the API, within the expiry time of the signature
the application checks the expiry of the cached signature against the current time and sees that it has not yet expired
the application uses the cached signature to make a request to the API, processing the result and presenting it to the user
A user requests a view in the application which requires the use of the API, after the expiry time of the signature
the application checks the expiry of the cached signature against the current time and sees that it has expired
the application requests a new signature from the authenticating server
the application uses the new signature to make a request to the API, processing the result and presenting it to the user