Mobile Integration
Integrating with the DeSo Identity on Mobile.
Last updated
Integrating with the DeSo Identity on Mobile.
Last updated
In the world of blockchain, user private keys are extremely sensitive information.
This is because, unlike Web2 password, private keys cannot be modified, which means that if somebody gets a hold of your private key, you're potentially forever vulnerable to an attack and there isn't much you can do unless you move your entire account to another private key.
We are firm believers that user primary keys should never be shared with third-party applications, regardless of their security practices, and so we created derived keys, which significantly lower attack vectors related to unauthorized access to user credentials.
Derived keys are impermanent and they usually automatically expire about 30 days after being issued.
Derived keys can also be de-authorized at any point, which we believe will allow for the creation of advanced security systems in the future that can mitigate the risks originating from key leakage.
After the Transaction Spending Limit
block height is reached, derived keys will need to be authorized to perform specific transaction types as well as more specific operations for Creator Coin, DAO Coin, and NFT transaction types.
Check out to learn how to construct the Transaction Spending Limit object.
A derived key is a pair of public and private cryptographic keys that are authorized to sign transactions on behalf of another key pair.
That is, if you hold a valid derived key of a user, you can submit a transaction signed by that derived key, and it will be regarded as a valid transaction as if it was made by that user.
This is particularly useful in mobile applications because it means you only have to interact with the DeSo Identity Service once, just to get the derived key of a user.
It also means that derived keys are extremely sensitive information and therefore should be handled in secure storage with the utmost caution, ideally by experienced software engineers.
The flow of using the derived keys is as follows:
Generate a derived key by making a call to window API endpoint
Construct a AuthorizeDerivedKey
transaction via Backend API through /api/v0/authorize-derived-key
Sign the AuthorizeDerivedKey
transaction with the derived key
Submit signed AuthorizeDerivedKey
transaction via /api/v0/submit-transaction
(Optional) Confirm that the derived key was successfully authorized through Backend API in /api/v0/get-user-derived-keys
In case your application requires offline signing e.g. when you’re a mobile client, identity can accommodate you with derived key material.
Once the user completes the identity flow, you’ll receive a response containing the derived keypair.
For simplicity, we list the response payload as a JSON object; however, you'll receive it as URL parameters in a callback.
Let’s take a look at these values:
accessSignature
is a proof of access, equal to an owner-signed digest of sha256(derivedPublicKey + expirationBlock +
transactionSpendingLimitBytes)
(For more details check out the implementation)
derivedPublicKeyBase58Check
and derivedSeedHex
is the derived keypair
expirationBlock
is a future block height, and represents the expiration “date” (block) of the derived key. Derived keys expire after about 30 days.
After that period, you will have to generate and authorize another derived key.
To check if a derived key is valid you should compare the current block height, e.g. taken from /api/v0/get-app-state
Backend API endpoint, with the expirationBlock
that you can find by querying the /api/v0/get-user-derived-keys
Backend API endpoint.
derivedJwt
is a JWT token with a month-long timeout signed by the derivedPublicKeyBase58Check
jwt
is a JWT token with a month-long timeout signed by the owner publicKeyBase58Check
network
is the network for which this derived key was generated
messagingKeyName
is the key name used for v3 messaging
messagingKeySignature
is the key signature used for v3 messaging
messagingPublicKeyBase58Check
is the public key used for v3 messaging
messagingPrivateKey
is the private key used for v3 messaging
publicKeyBase58Check
is the public key that is the parent of this derived key.
transactionSpendingLimitHex
is a hex string representing the TransactionSpendingLimit for this derived key.
Before any signing can happen, a derived key must first be activated by submitting an authorizeDerivedKey
transaction, containing the accessSignature
, derivedPublicKeyBase58Check
, expirationBlock
, transactionSpendingLimitHex
and publicKeyBase58Check
.
To make the transaction, make a request to the /api/v0/authorize-derived-key
Backend API endpoint.
If you set DerivedKeySignature: true
when making the Backend API request, you can sign the authorize transaction with the derived key right away.
To help you get started with the authorizeDerivedKey
transaction, we made this node.js code snippet in examples repository that shows this flow.
If everything worked, you should see the derived key listed in the response to the /api/v0/get-user-derived-keys
endpoint with a payload of PublicKeyBase58Check
set to owner user public key.
Additionally, see the implementation of AuthorizeDerivedKey in the DeSo developer hub here.
While powerful, this model has a limitation.
Namely, it requires the user to have some balance to execute the authorizeDerivedKey
transaction.
This poses a limitation as you won't be able to authorize a derived key for new users who might not have balance in their accounts.
However, in practice, there is no use for derived keys unless the user has some non-zero balance in their account. Otherwise, they wouldn't be able to submit any transactions in the first place.
One possible remedy to this limitation is to send the authorizeDerivedKey
transaction only when the user wants to perform an action and has sufficient balance, such as giving a like, making a follow, etc.
Another approach is to write a hook that sends the authorizeDerivedKey
transaction in the background whenever user receives sufficient balance.
This simple background mechanism should mitigate most UX issues.
The private key derivedSeedHex
embedded in the response from Identity's /derive
can be used to sign transactions on behalf of the publicKeyBase58Check
owner.
To achieve this, you should construct transactions in the Backend API as if made by the owner’s public key.
You then need to append a field to transaction’s ExtraData["DerivedPublicKey"]
with value set to the derived public key in compressed byte format (33 bytes array) encoded as hex string.
Check out this node.js code snippet in the examples repository for help with compressing the derived public key.
If you have trouble de/serializing transactions to add the “DerivedPublicKey”
to ExtraData, you can use a backend endpoint /api/v0/append-extra-data
and pass the hex of the transaction and the derived public key like this:
Request
Because of intricacies with transaction fees and ExtraData, you should increase minFeeRateNanosPerKb
to something like 12500
from 10000
when constructing the transaction.
Otherwise, you might get an error while submitting transactions indicating that transaction fee is too low.
Once you have the transaction hex with the derived key in ExtraData, you can sign the transaction with the derivedSeedHex
you’ve received from identity.
You can use the signing code from the authorize-derived-key
example node.js code snippet.
You can also find this example implementation in Go of signing with a derived key corresponding to the admin backend endpoint /api/v0/admin/test-sign-transaction-with-derived-key
.
Once signed, the transaction can be submitted through the /api/v0/submit-transacton
per usual.
Note that we didn’t need to communicate with the DeSo Identity at any point in this process.
You can use derived keys to encrypt/decrypt messages on the DeSo blockchain. For more information on our messaging protocol check out the section.
In order to encrypt/decrypt messages you will need to get shared secrets for each messaging partner of your user.
Once you get the shared secrets you can use them to encrypt/decrypt messages.
To help you code this flow, we made a node.js code snippet in the examples repository which displays our messaging protocol.
Identity also offers support for webview, but there are some differences needed in order to fully integrate.
Major differences:
There is no need to run an iframe context. You will send all messages to one context running in a webview.
Your webview context will need to have an additional parameter ?webview=true
Depending on your mobile development framework, you need to make sure messages to and from the webview are being registered appropriately. Currently iOS, Android, and React Native webviews are supported.
To get a derived key for a user, launch the window API endpoint with a callback at:
To get the shared secrets, you can submit requests to the endpoint in the window API.