MFA Transaction Signing
Enrol a user, set a PIN, and sign a transaction from C#, on Android and iOS alike.
Overview
Section titled “Overview”Read MFA Transaction Signing first for the three-call flow and what the token proves.
Every call returns JSON as a string, which you parse with the matching result type. They are synchronous and they do network I/O, so call them from a coroutine or a worker rather than from a frame you care about.
Basic Usage
Section titled “Basic Usage”using Byteria.SDK;
// 1. Once per (user, device), after login. No biometric prompt appears here.MfaResult enrolment = MfaResult.Parse(AlphynSDK.EnrollForMfa(userId));if (!enrolment.success) { Debug.LogWarning($"enrol failed: {enrolment.errorCode}");}
// 2. Set or change the PIN. Verified and hashed ON THE SERVER.char[] newPin = pinInput.text.ToCharArray();MfaResult pinResult = MfaResult.Parse(AlphynSDK.SetMfaPin(userId, newPin));
// 3. Per transaction, after the user clears your confirmation screen.char[] pin = pinInput.text.ToCharArray();string context = "{\"amount\":\"250.00\",\"currency\":\"TRY\",\"toIBAN\":\"TR12…\"}";
ActionVerificationResult result = ActionVerificationResult.Parse(AlphynSDK.SignAction(userId, "TRANSFER", context, pin));
if (result.success) { StartCoroutine(SendToYourBackend(result.verificationToken));}SetMfaPin and SignAction zero every char[] they are given before returning, on every path.
Build the array from your input field and pass it; do not keep a string copy, because a C# string
is immutable and cannot be wiped.
Methods
Section titled “Methods”public static string EnrollForMfa(string userId)
public static string SetMfaPin(string userId, char[] newPin, char[] oldPin = null)
public static string SignAction(string userId, string actionLabel, string contextJson, char[] pin = null, AlphynSubject subject = null)Parameters
Section titled “Parameters”| Parameter | Type | Notes |
|---|---|---|
userId | string | your identifier for the logged-in user, not one Alphyn issues |
newPin / oldPin | char[] | zeroed by the call. Omit oldPin on a first set |
actionLabel | string | your own name for the operation, e.g. TRANSFER |
contextJson | string | the transaction as a JSON object. Its hash is bound into the signature |
pin | char[] | optional. Omitting it omits the factor rather than failing |
subject | AlphynSubject | optional. null is byte-identical to declaring nothing |
MfaResult
Section titled “MfaResult”success, errorCode, errorMessage, securityLevel, enrollmentId. Parse with
MfaResult.Parse(json).
ActionVerificationResult
Section titled “ActionVerificationResult”success, verificationToken, expiresAtMs, errorCode, errorMessage. Parse with
ActionVerificationResult.Parse(json).
Read the token from verificationToken. It is the whole JWT and it is what your backend verifies;
it is not a display value.
Declaring an identity
Section titled “Declaring an identity”var subject = new AlphynSubject.Builder() .Tc("10000000146") .Phone("+905342223344") .Build();
ActionVerificationResult result = ActionVerificationResult.Parse( AlphynSDK.SignAction(userId, "TRANSFER", context, pin, subject));Build() never throws and never fails, for any input. AlphynSubject carries the three values;
it does not validate or hash them. That work belongs to the native core, so that the accepted forms
have one implementation per platform rather than a third one in C# that could disagree with the other
two.
A field that does not conform is dropped, never corrected, and a subject in which nothing survived produces a request byte-identical to one that declared none. See Subject identity for the accepted forms and for why a token must be treated as identifying data.
If the running Alphyn core is older than subject support, the identity is dropped, the transaction proceeds, and the SDK logs a single warning. Declaring an identity can never cost a transaction.
Use Cases
Section titled “Use Cases”- Signing an in-game purchase, a withdrawal or an account change so your backend can prove afterwards that a specific user’s device authorised those exact values
- Adding a second factor to a high-risk action without an SMS round trip
- Correlating a signed transaction with a person across institutions, through a subject token
Example: signing a transfer end to end
Section titled “Example: signing a transfer end to end”IEnumerator ConfirmTransfer(string userId, string iban, string amount) { char[] pin = pinInput.text.ToCharArray(); string context = $"{{\"amount\":\"{amount}\",\"currency\":\"TRY\",\"toIBAN\":\"{iban}\"}}";
var subject = new AlphynSubject.Builder().Tc(customerTckn).Build();
ActionVerificationResult result = ActionVerificationResult.Parse( AlphynSDK.SignAction(userId, "TRANSFER", context, pin, subject));
if (!result.success) { // THREAT_DETECTED is a refusal, not a transport failure. Do not retry silently. ShowError(result.errorCode); yield break; }
// Your backend validates this token before it moves anything. yield return YourApi.Transfer(iban, amount, result.verificationToken);}The token is evidence, not a decision. Your backend must validate it server-side and compare the echoed context against the transfer it is about to perform; see Backend verification.