zkLogin wallet API

User-controlled wallets with web2 simplicity

Overview

zkLogin is a Sui primitive that allows users to transact on Sui using the OAuth login flows they're familiar with, eliminating the friction of handling cryptographic keys or remembering mnemonics. zkLogin can be thought of as a two-factor authentication scheme, since sending a transaction requires both a credential from a recent OAuth login and a salt not managed by the OAuth provider. To learn more, see Mysten's zkLogin doc.

We've also created a tutorial that helps you very quickly create your first zkLogin app that interacts with Shinami Gas Station for transaction sponsorship.

Use Cases

When you want to offer your users a non-custodial wallet that doesn't require them to remember mnemonics and pass-phrases - only their OAuth provider password.

Authentication, Rate Limits, and Error Handling

Authentication

You authenticate via a Wallet Services access key passed in a header ('X-Api-Key: ACCESS_KEY') or in the request URL: https://api.shinami.com/{{zkWallet|zkprover}}/v1/ACCESS_KEY. Unlike for Node Service and Gas Station, access keys are not network-specific (Devnet, Testnet, Mainnet). In your Shinami dashboard you can create multiple keys per network if needed.

Error Handling

See our Error Reference for the HTTP and JSON-RPC errors you may receive. Common zkLogin Wallet API errors include:

CodeError MessageWhat To Do
-32602"message":"Invalid params","data":{"details":"{\"name\":\"InputValidationError\",\"message\":\"The issuer Online JWT Builder is not supported\"}Use an OAuth provider from the list of supported providers.
-32602'{"name":"InputValidationError","message":"Nonce TjpyZAr252rQ8dzOwoA1vioMTzY does not match computed nonce LAo4DvFaHZ88kREHZmRqgz8EBVw"}'Ensure that the jwtRandomness value was the same one used to prepare the nonce used in the OAuth flow that generated the jwt that's also being passed to the function.

🚧

Security Warning: Do not call this API from your frontend.

We recommend having your backend server integrate with Shinami's zkLogin wallet API to prevent exposing any access keys on the frontend.

zkLogin Addresses

A zkLogin wallet address is derived from iss, aud, sub, salt, where:

  • iss: The open id provider.
  • aud : The unique identifier assigned to your application by the OAuth provider.
  • sub: The OAuth provider's locally unique and never reassigned identifier for the user.
  • salt: A consistent, ideally unique, value used to unlink the OAuth identifier with the on-chain address.

As a result, a user will have a new zkLogin wallet address if any of the above values change. For example, if one of your users logs in via Google and then Twitch and you use both credentials with zkLogin, each credential will be linked to a different address. To learn more, see Mysten's zkLogin doc.


zkLogin wallet service methods

shinami_zkw_getOrCreateZkLoginWallet

Description
Retrieves a zkLogin wallet along with its associated salt, creating a new wallet if necessary. This method provides the option to create and use multiple zkLogin wallets per (user, OAuth provider) pair by using the optional subWwallet parameter. Note that your users will already have a different zkLogin wallet for each OAuth provider they use, whose jwt you pass to this method (see zkLogin Addresses for more details).

The example below uses the Shinami Clients SDK.

Request Parameters

NameTypeDescription
jwtStringA valid JWT signed by one of the supported OpenID providers. The JWT nonce must be prepared according to the zkLogin requirements.
keyClaimNameStringOptional. The claim name in the JWT that identifies a particular user. Defaults to "sub". Currently, Mysten's zkLogin implementation only supports the "sub" field of the OpenID spec. This parameter allows for forward compatibility as the implementation expands to support other values.
subWalletIntegerOptional. The sub-wallet id, which enables the same OpenID user to have more than one wallet addresses. Defaults to 0

Example Request Template

Replace all instances of {{name}} with the actual value for that name

 curl https://api.shinami.com/zkwallet/v1 \
 -X POST \
 -H 'X-API-Key: {{walletAccessKey}}' \
 -H 'Content-Type: application/json' \
 -d '{
         "jsonrpc":"2.0", 
         "method":"shinami_zkw_getOrCreateZkLoginWallet", 
         "params":[
             "{{signedJWTToken}}"
         ], 
         "id":1
      }'
import { ZkWalletClient } from "@shinami/clients";

// Obtain wallet access key from your Shinami web portal.
const zkw = new ZkWalletClient({{walletAccessKey}});

// Prepare a nonce according to the zkLogin requirements.
// Obtain a valid jwt with that nonce from a supported OpenID provider.

// Get zkLogin wallet salt.
await zkw.getOrCreateZkLoginWallet({{jwt}});

Example Response

{
    "jsonrpc": "2.0",
    "result": {
        "userId": {
            "iss": "https://id.twitch.tv/oauth2",
            "aud": "2bc0920c90ufn0adomxlca3pldbdpo",
            "keyClaimName": "sub",
            "keyClaimValue": "984333370"
        },
        "subWallet": 0,
        "salt": "kL+fRWN8888cKl5D72qzCQ==",
        "address": "0x6a7b07da9d2c210bbbe044dbe29f0c5ae20444584a4d8ee9a804839f8256ea3c"
    },
    "id": 1
}
{
    userId: {
        iss: 'https://id.twitch.tv/oauth2',
        aud: '2bc0920c90ufn0adomxlca3pldbdpo',
        keyClaimName: 'sub',
        keyClaimValue: '984333370'
    },
    subWallet: 0,
    salt: 192403790493605555550623021243959522057n,
    address: '0x6a7b07da9d2c210bbbe044dbe29f0c5ae20444584a4d8ee9a804839f8256ea3c'
}

Response Data

NameTypeDescription
userIdObjectThe OAuth user information used to create the wallet.
subWalletIntegerThe subWallet number.
saltcURL: Base64 encoded String SDK: BigIntThe salt associated with this zkLogin wallet.
addressHex encoded StringThe Sui zkLogin address of this wallet.

zkProver service methods

shinami_zkp_createZkLoginProof

Description
Generate a zkLogin proof prior to signing and executing a transaction. The example below uses the Shinami Clients SDK.

Request Parameters

NameTypeDescription
jwtStringA valid JWT signed by one of the supported OpenID providers. The JWT nonce must be prepared according to the zkLogin requirements.
maxEpochcURL: String SDK: IntThe max epoch used to prepare the JWT nonce. This governs the expiration of the zkLogin proof.
extendedEphemeralPublicKeycURL: Base64 encoded String SDK: PublicKeyThe ephemeral public key used to prepare the JWT nonce. Must be prepended with the scheme flag and encoded in Base64 (see example here). The corresponding private key must be used to sign any transactions to be executed with this proof.
jwtRandomnesscURL: Base64 encoded String SDK: BigIntThe random bytes used to prepare the JWT nonce (see example here).
saltcURL: Base64 encoded String SDK: BigIntThe zkLogin wallet salt. Together with the provided JWT, this determines the zkLogin on-chain address.
keyClaimNameStringOptional. The claim name in the JWT that identifies a particular user. Defaults to "sub". Currently, Mysten's zkLogin implementation only supports the sub field of the OpenID spec. This parameter allows for forward compatibility as the implementation expands to support other values.

Example Request Template

Replace all instances of {{name}} with the actual value for that name

curl https://api.shinami.com/zkprover/v1 \
-X POST \
-H 'X-API-Key: {{walletAccessKey}}' \
-H 'Content-Type: application/json' \
-d '{
        "jsonrpc":"2.0", 
        "method":"shinami_zkp_createZkLoginProof", 
        "params":[
            "{{jwt}}",
            "{{maxEpoch}}",
            "{{extendedEphemeralPublicKey}}",
            "{{jwtRandomness}}",
            "{{salt}}"
        ], 
        "id":1
    }'
import { ZkProverClient } from "@shinami/clients";

// Obtain wallet access key from your Shinami web portal.
const zkp = new ZkProverClient({{walletAccessKey}});

// Create a zkProof.
await zkp.createZkLoginProof(
    {{jwt}},
    {{maxEpoch}},
    {{ephemeralPublicKey}},
    {{jwtRandomness}},
    {{salt}}
);

// Now you can sign transaction blocks with ephemeralPrivateKey, and assemble the zkLogin signature
// using zkProof.

Example Response

{
    "jsonrpc": "2.0",
    "result": {
        "zkProof": {
            "proofPoints": {
                "a": ["15523188928150068463877187176143113666714843703470604151076285692983325640642", "5937622317780822197753258881898720685630444182643789312895382585679701582730", "1"],
                "b": [
                    ["16826302723856343423452057269835204629749355045593813315170205467027472681113", "13797818130832460450334887874511731864855590610477696974834238052347712422314"],
                    ["13373917712679082794928414217966585760669198351828608413595476883128268622714", "5700527829855762859349841977943997112007134227264278415875624634861579977183"],
                    ["1", "0"]
                ],
                "c": ["7520248514700601656024563691610669758825183429353083260336955084416144661718", "20552359067831153630006195193902483617859079319246848227965146473634030062290", "1"]
            },
            "issBase64Details": {
                "value": "wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw",
                "indexMod4": 2
            },
            "headerBase64": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ"
        }
    },
    "id": 1
}
{
    proofPoints: {
        a: [
            '10210145730043037811940974600447596138332245137712632111543948579663620583434',
            '7161160787659733995589070724990899004457677439433421417304252171408748983773',
            '1'
        ],
        b: [ [Array], [Array], [Array] ],
        c: [
            '14336916288409630215040261300089886420211729238372809076105326107110995622366',
            '16791539167604801843541798961147781044566621780138018818605704529730677460898',
            '1'
        ]
    },
    issBase64Details: {
        value: 'wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw',
        indexMod4: 2
    },
    headerBase64: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ'
}

Response Data

TypeDescription
JSON objectThe zkLogin proof for the given JWT.