Background
Sign In With Stellar requires the wallet to sign a server-generated message. The backend must issue a time-limited, single-use challenge string tied to the requesting wallet address. This is the first step of the two-step auth flow.
Proposed Steps
- Create
POST /auth/challenge route
- Accept
{ address: string } in the request body
- Validate that
address is a valid Stellar public key (using StrKey.isValidEd25519PublicKey from @stellar/stellar-sdk)
- Generate a cryptographically random nonce (
crypto.randomBytes(32).toString('hex'))
- Persist an
AuthNonce record with expiresAt = now + 5 minutes
- Return a structured challenge message that the wallet will sign
- Clean up expired nonces on each call
Acceptance Criteria
POST /auth/challenge with a valid Stellar address returns 200 with { message, nonce, expiresAt }
POST /auth/challenge with an invalid address returns 400 with a clear error
- Nonce is persisted to
AuthNonce table
- Expired nonces are cleaned up before each new challenge is generated
- The challenge message format is deterministic and matches what the frontend signs
Background
Sign In With Stellar requires the wallet to sign a server-generated message. The backend must issue a time-limited, single-use challenge string tied to the requesting wallet address. This is the first step of the two-step auth flow.
Proposed Steps
POST /auth/challengeroute{ address: string }in the request bodyaddressis a valid Stellar public key (usingStrKey.isValidEd25519PublicKeyfrom@stellar/stellar-sdk)crypto.randomBytes(32).toString('hex'))AuthNoncerecord withexpiresAt = now + 5 minutesAcceptance Criteria
POST /auth/challengewith a valid Stellar address returns200with{ message, nonce, expiresAt }POST /auth/challengewith an invalid address returns400with a clear errorAuthNoncetable