Authentication
The application embedding the Saakuru Mobile SDK needs to provide a SSO endpoint for the SDK backend to verify user information. The response from the endpoint should be similar to Google’s ID token, such as sub, iat, exp, email, name, and aud.
{
"sub": "user ID",
"iat": "issue time",
"exp": "expiry time",
"email": "user email",
"name": "user name",
"aud": "audience ID"
}
- sub is the user ID of the application. It should be unique and always the same.
- iat and exp are the issue and expire time. The token is valid only within this timeframe.
email is the email of the user. - name is an optional field. It is the name of the user.
- aud is the audience ID. It is a predefined constant used to prevent the token issued to other applications being used to access data about the same user.
Both the audience ID and token info url will need to be provided for integration.
Sequence Diagram
- User logins to the application and gets a token.
- The token is passed to SDK ssoLogin API.
- SDK verifies the user info by querying the SSO endpoint (tokenInfoURL).
- Upon validation, a session is created for the application to use the SDK and its APIs.
Emails
The SDK is able to send the following system emails on behalf of the application using generic templates:
Email Name | Description |
---|---|
Verification Code - Resetting Signature | Temporary code sent to user's email address for authentication purposes when there is a request to reset the signature. |
Verification Code - Linking Existing Saakuru Account | Temporary code sent to user's email address for authentication purposes when attempting to link to an existing Saakuru account |
Signature - Failed to Reset | Notification sent to user's email that the signature reset process was not successfully completed |
Signature Updated | Notification sent to user's email that the signature reset process was successfully completed |
Signature Recovery Questions Updated | Notification sent to user's email that the signature recovery questions were successfully updated |
Customization to the email template, sender name, and sender address is possible.
Notifications
The application can receive various user events from the SDK by setting up a webhook. The application can push notifications to users based on the event type.
Event format includes fields such as user, title, body, and data.
{
"user": <user id, the sub value from SSO tokenInfoURL>,
"title": ,
"body": ,
"data":
}
Below is the list of event types, format details, and sample messages:
Notification | Sample Message Format |
---|---|
Transaction Sent | { "user": "987654321", "title": "Sent ONE", "body": "0.45976983 ONE has been sent to Jack || 0xb0....55a7", "data": { "op": "txn.sent", "time": "1660893183", "content": { "bip44": "1023", "chainId": "1666600000", "txnHash": "0x231...", "symbol": "ONE", "amount": "0.45976983", "walletAddress": "0xabc1...", "otherWallet": "0xb0....55a7", "to": "Jack || 0xb0....55a7" } } } |
Transaction Received | { "user": "987654321", "title": "Received ONE", "body": "0.45976983 ONE has been received from Alex || 0xb0....55a7", "data": { "op": "txn.received", "time": "1660893183", "content": { "bip44": "1023", "chainId": "1666600000", "txnHash": "0x231...", "symbol": "ONE", "amount": "0.45976983", "walletAddress": "0xabc1...", "otherWallet": "0xb0....55a7", "from": "Alex || 0xb0....55a7" } } } |
Transaction Cancelled | { "user": "987654321", "title": "Transaction Cancelled", "body": "Send 0.45976983 ONE to Jason || 0xb0....55a7", "data": { "op": "txn.cancelled", "time": "1660893183", "content": { "bip44": "1023", "chainId": "1666600000", "txnHash": "0x231...", "symbol": "ONE", "amount": "0.45976983", "walletAddress": "0xabc1...", "otherWallet": "0xb0....55a7", "to": "Jack || 0xb0....55a7" } } } |
Transfer Completed | { "user": "987654321", "title": "Transaction Confirmed", "body": "0.45976983 ONE from Harmony savings to Harmony staking", "data": { "op": "txn.internal", "time": "1660893183", "content": { "bip44": "1023", "chainId": "1666600000", "txnHash": "0x231...", "symbol": "ONE", "amount": "0.45976983", "fromWalletAddress": "0xabc1...", "fromWalletName": "Harmony savings", "toWalletAddress": "0xb0....55a7", "toWalletName": "Harmony staking" } } } |
Swap Completed | { "user": "987654321", "title": "Swap Completed", "body": "Swap from 0.457 ONE to MATIC is completed. You received 0.001 MATIC", "data": { "op": "txn.swap", "time": "1660893183", "content": { "bip44": "1023", "chainId": "1666600000", "txnHash": "0x231...", "walletAddress": "0xabc1..." "swapFrom": "ONE" "swapFromAmount": "0.457" "swapTo": "MATIC" "swapToAmount": "0.001" } } } |
M1 Buy Crypto Confirmed | { "user": "987654321", "title": "Buying BTC confirmed", "body": "Buying BTC transaction is confirmed and being processed.", "data": { "op": "buy.confirm", "time": "1695033023537” "content": { "symbol": "BTC”, "amount": 0.00169875 } } } |
M1 Buy Crypto Completed | { "user": "987654321", "title": "Buying BTC completed", "body": "You have successfully bought and received 0.00169875 BTC.", "data": { "op": "buy.success", "time": "1695033023537” "content": { "symbol": "BTC”, "amount": 0.00169875 } } } |
M1 Buy Crypto Completed & Has TomoOne | { "user": "987654321", "title": "Buying BTC completed", "body": "You have successfully bought and received 0.00169875 BTC. Your TomoOne HP increased 500 points", "data": { "op": "buy.success", "time": "1695033023537” "content": { "symbol": "BTC”, "amount": 0.00169875, “addedPoints”: “500” } } } |
M1 Buy Crypto Failed | { "user": "987654321", "title": "Buying BTC failed", "body": "Buying BTC failed. Check email for more details from service provider.", "data": { "op": "buy.fail", "time": "1695033023537” "content": { "symbol": "BTC”, "amount": 0.00169875 } } } |
M1 Sell Crypto Completed | { "user": "987654321", "title": "Selling BTC completed", "body": "You have successfully sold 0.00169875 BTC.", "data": { "op": "sell.success", "time": "1695033023537” "content": { "symbol": "BTC”, "amount": 0.00169875 } } } |
M1 Sell Crypto Completed & Has TomoOne | { "user": "987654321", "title": "Selling BTC completed", "body": "You have successfully sold 0.00169875 BTC. Your TomoOne HP increased 500 points", "data": { "op": "sell.success", "time": "1695033023537” "content": { "symbol": "BTC”, "amount": 0.00169875, “addedPoints”: “500” } } } |
M1 Sell Crypto Failed | { "user": "987654321", "title": "Selling BTC failed", "body": "Selling BTC failed. Check email for more details from service provider.", "data": { "op": "sell.failed", "time": "1695033023537” "content": { "symbol": "BTC”, "amount": 0.00169875 } } } |
M1 Swap KYC success | { "user": "987654321", "title": "Swap KYC status", "body": "Your KYC success", "data": { "op": "kyc.success", "time": "1695031101879” "content": { } } } |
M1 Swap KYC Failed | { "user": "987654321", "title": "Swap KYC status", "body": "Your KYC failed", "data": { "op": "kyc.failed", "time": "1695031101879” "content": { } } } |
M1 Swap Status Confirmed | { "user": "987654321", "title": "Swap confirmed", "body": "Your swap from 1INCH to BNB is confirmed, processing withdrawal.", "data": { "op": "swap.ProcessingWithdrawal", "time": "1695036577653” "content": { "status": "ProcessingWithdrawal”, "symbolA": “1INCH”, "symbolB": “BNB” } } } |
M1 Swap Status Completed | { "user": "987654321", "title": "Swap completed", "body": "You have successfully swapped 1INCH to BNB. Withdrawal is now being processed.", "data": { "op": "swap.ProcessingWithdrawal", "time": "1695036577653” "content": { "status": "ProcessingWithdrawal”, "symbolA": “1INCH”, "symbolB": “BNB” } } } |
M1 Swap Status Completed & Has TomoOne | { "user": "987654321", "title": "Swap completed", "body": "You have successfully swapped 1INCH to BNB. Withdrawal is now being processed. Your TomoOne HP increased 500 points", "data": { "op": "swap.ProcessingWithdrawal", "time": "1695036577653” "content": { "status": "ProcessingWithdrawal”, "symbolA": “1INCH”, "symbolB": “BNB”, “addedPoints”: “500” } } } |
M1 Swap Status Failed (Exceed Slippage Reason) | { "user": "987654321", "title": "Swap failed", "body": "Failed to swap 1INCH to BNB due to "a higher slippage" OR "a different deposit amount".", "data": { "op": "swap.ExceedSlippage", "time": "1695036577653” "content": { "status": "ExceedSlippage”, "symbolA": “1INCH”, "symbolB": “BNB” } } } |
M1 Swap Status Failed (Different Deposit Amount Reason) | { "user": "987654321", "title": "Swap failed", "body": "Failed to swap 1INCH to BNB due to "a higher slippage" OR "a different deposit amount".", "data": { "op": "swap.DifferentDepositAmount", "time": "1695036577653” "content": { "status": "DifferentDepositAmount”, "symbolA": “1INCH”, "symbolB": “BNB” } } } |
Considerations
Error Handling
- Handle invalid token request, tokenInfoURL should return error and non 200 http status response.
- Handle scenario where user failed to reset signature due to exceeding the limit of verification attempts. SDK will notify the application to logout the user.
- Handle max concurrent sessions and logout the user appropriately.
Security
- Protect the tokenInfoURL endpoint and notification webhook by whitelisting the SDK server IPs or assigning API keys.
- Token should be unique, generated by non-deterministic algorithm, or digitally signed with a small window of validate time period.
- Monitor traffic to detect then stop bot and malicious requests.
- Always logout from the SDK when the user logout from the application.
Session Management
- A limit should be set for the maximum number of concurrent SDK sessions allowed.
- When the number of concurrent sessions exceeds, the oldest idle session will be removed.
- The default is 1 and this is the recommended value for better security so the system doesn't allow multiple sessions to coexist.
- The value should match what is allowed for the application.
Testing and Validation
- Thoroughly test the integration, especially the authentication and notification mechanisms, to ensure data mapping is accurate and be able to notify the right user.
- Validate the content of the email includes the app logo, app name, support email, copyright information, and email sender are all correct.
- Ensure the availability of the SSO server and webhook to provide a reliable service for the SDK backend.