Backend Verification
What your server does with the token signAction returns, and where it reads the subject.
Overview
Section titled “Overview”The token the SDK hands your application is not a decision. It is evidence, and it is only worth anything once your backend has validated it server-to-server against the Alphyn backend. A client that reports “signed successfully” is a client, and a compromised one says the same thing.
The flow:
- your app calls
signActionand receivesverificationToken; - your app sends that token to your backend along with the transaction it is about to perform;
- your backend calls Alphyn’s verification endpoint with its Backend verify key;
- your backend compares what Alphyn echoes back against the transaction it was asked to perform;
- only then does it move the money.
Steps 4 and 5 are the ones that matter. A backend that calls the endpoint and acts on valid: true
alone has verified that a transaction was signed, not this one.
The request
Section titled “The request”POST https://alphyn-attestation-api.byterialab.com/api/public/action/backend-verifyX-API-Key: <your Backend verify key>Content-Type: application/json
{ "verificationToken": "<the token from signAction>" }The Backend verify key is issued per registered app in the Alphyn dashboard and is not the API key your build registration uses. It belongs on your server and nowhere near your application bundle.
The response
Section titled “The response”When the token is valid:
| Field | What it is for |
|---|---|
valid | true. Necessary, nowhere near sufficient |
verificationId | unique identifier for this verification |
deviceId | the device that signed |
appHash | the application hash, for app identity |
packageName | the application’s package name or bundle identifier |
contextHash | hash of the context that was signed |
actionLabel | the label you passed, for example TRANSFER |
context | the context that was signed, echoed back |
issuedAt / expiresAt | the token’s validity window |
What your backend must check
Section titled “What your backend must check”Check all four. Each of them is a real attack if you skip it.
1. contextHash matches the transaction you are about to perform. This is the whole point. Bind
the token to the exact amount and destination in front of you, not merely to “a transfer”. Without
this check a token signed for a 10 TRY transfer authorises a 100 000 TRY one.
2. expiresAt has not passed. Tokens are short-lived by design; treat a stale one as unsigned.
3. actionLabel is the operation you are executing. A token signed for LOGIN is not
authorisation for WITHDRAW.
4. packageName and appHash are yours. They are what stops a token minted by another
application from being spent on yours.
Where the subject appears
Section titled “Where the subject appears”The subject tokens are not a separate field. They ride inside the transaction context, so they
come back inside the echoed context, under a nested subject object:
{ "valid": true, "actionLabel": "TRANSFER", "context": { "amount": "250.00", "currency": "TRY", "subject": { "tc": "0247d10cbc2b05efa49fe02b15ad274d15031abf05a87fffcf461795ccbc6901", "phone": "e47be99e43d11b27bd452dfe825bb979dacc4e9aec9ec7c92dc7547d6a250561" } }}Because they travel inside the context, they are covered by the same signature and by the same
contextHash check as every other field. A subject that was altered in flight fails check 1 above,
along with everything else in the context.
A field that was dropped as malformed is absent from that object rather than present and empty. Do not read an empty string as “declared but invalid”: from your backend’s side, dropped and never declared are the same thing, deliberately.
These tokens are identifying data. They are stable pseudonyms, not anonymised values, and the valid national-identifier space is small enough to enumerate. Whatever your policy is for storing a national identification number applies to its token. See Subject identity.
What this endpoint does not tell you
Section titled “What this endpoint does not tell you”It does not tell you whether the user is allowed to make this transfer, whether the account has the balance, or whether your own fraud rules are satisfied. It tells you that a specific enrolled user’s device signed a specific context at a specific time, on a device whose state Alphyn had attested. Every business decision is still yours.