Browser Extension
Sign-in
Prove a user controls an XRP Ledger address with CAIP-122 sign-in, without moving funds.
signIn() lets a user prove they control an address. It needs a connected site and the user's approval.
There is deliberately no signMessage: a signature over an arbitrary string could be replayed against other sites. Sign-in messages are bound to your site, the chain and a nonce.
interface SignInParams {
statement?: string // shown to the user; up to 512 characters
nonce?: string // up to 128 characters; Joey generates one if omitted
resources?: string[] // up to 16 URIs, shown and included in the message
}
type SignInResult = Caip122SignInResult | ChallengeSignInResult
interface Caip122SignInResult {
address: string
publicKey: string
signature: string
message: string
mode?: 'caip122'
}
interface ChallengeSignInResult {
address: string
signedTx: string
mode: 'challenge-v1'
}
Usage
The result's shape depends on the account the user chooses, so always check it with isChallengeSignIn:
import { isChallengeSignIn } from '@joeywallet/wallet-sdk'
const result = await joey.signIn({
statement: 'Sign in to Example',
nonce: nonceFromYourServer,
})
if (isChallengeSignIn(result)) {
// Ledger hardware account: verify result.signedTx on your server
} else {
// Software account: verify result.signature over result.message with result.publicKey
}
The CAIP-122 message
Joey builds the message itself. Lines are joined with \n:
<host> wants you to sign in with your XRPL account:
<address>
<statement>
URI: <origin>
Version: 1
Chain ID: xrpl:<networkId>
Nonce: <nonce>
Issued At: <ISO-8601 timestamp>
Resources:
- <uri>
The statement block appears only if you pass a statement, and the Resources block only if you pass resources.
Verifying on your server
- Parse
messageand check the host, URI, chain ID, nonce and issue time against what you expect. - Check that
publicKeyderivesaddress. - Verify
signatureover the UTF-8 bytes ofmessage, usingpublicKey. The signature covers the message bytes directly, so it can never be valid as a transaction signature.
Ledger challenge sign-in
Ledger devices can't sign arbitrary messages, so Joey asks a Ledger account to sign a challenge transaction instead (mode: 'challenge-v1'):
- The transaction is a 1-drop
Paymentfrom the account to itself withFee: '10'andSequence: 0, so it can never be applied on-ledger. - Its memo contains the hex-encoded JSON
{"wallet":"joey","challenge":"<nonce>"}. signedTxis the JSON of the signed transaction. To verify: parse it, check the memo's challenge, verify the signature, and bind the session to the account that actually signed.
This is the same format the Joey mobile app returns for WalletConnect sign-in, so one server-side verifier can handle both.