Auth (Holder Sign-In)
Endpoint reference: ⚠️ Mostly informational for store builders. The auth endpoints below are how holders authenticate to the Dr Green DAPP UI to generate API keys. As a store builder, you don’t call these directly — you receive the resultingapiKey+secretKeypair from the holder. This page exists so you understand where the keys come from, and so you can build a holder-onboarding flow if you offer one in your store.
The flow at a glance
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /auth/nonce | None | Generate a nonce for wallet signing |
POST | /auth/dapp/signIn | None | Exchange a wallet signature for a JWT |
POST | /auth/signIn | None | Admin / staff login (NOT for holders or stores) |
GET | /auth/verifyEmail | None | Email verification callback (out of band) |
GET | /auth/resendEmail | None | Re-send verification email |
⚠️POST /auth/signInis for Dr Green admin/staff accounts (SUPERADMIN,ADMIN,SUBADMIN,MANAGERroles). Holders (USERrole) use/auth/dapp/signIninstead. Don’t confuse the two.
POST /auth/nonce — get a nonce
Returns a single-use nonce string that must be included in the message the holder’s wallet signs.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
walletAddress | string | ✅ | Lowercased Ethereum address |
No request signing required
This is an unauthenticated endpoint. Nox-auth-apikey or x-auth-signature headers needed.
Response
201 Created with the nonce.
🔒 Exact response shape not yet captured live — likely { data: { nonce: "abc123..." } } based on the rest of the API’s envelope conventions.
Nonce semantics
- Single-use. Once consumed by
/auth/dapp/signIn, the same nonce can’t be reused. - Time-bound. Likely expires after a short window (5–15 minutes is typical). Confirm with backend if precise.
- Per-wallet. Issued for one specific
walletAddressand only valid for that address’s signature.
POST /auth/dapp/signIn — wallet sign-in
Exchange a wallet-signed nonce for a JWT.
Request body
PerSignInDto:
| Field | Type | Required | Notes |
|---|---|---|---|
walletAddress | string | ✅ | Same as the nonce was issued for |
nonce | string | ✅ | The exact value returned by /auth/nonce |
signature | string | ✅ | The hex-encoded ECDSA signature from the wallet (personal_sign style) |
Response
201 Created with a JWT.
🔒 Exact response shape pending live capture. Conventional shape:
What the holder signs
The exact message the wallet signs is determined by the DAPP UI. Based on backend code patterns and SIWE conventions, the message is approximately:🔒 The exact text including line breaks and punctuation is not formally documented and must match byte-for-byte what the backend reconstructs. If you build a holder-facing wallet-signin flow in your store, don’t reverse-engineer the message format — instead, either:For most store integrations, option 1 is the right call — let Dr Green handle wallet auth, and consume the resulting keys.
- Direct the holder to the DAPP UI to authenticate and generate keys (recommended), or
- Coordinate with Dr Green to expose the canonical message format for re-implementation
When a store builder might care
Most stores never call these endpoints. Two situations where you would:Situation 1: White-label holder onboarding
If your store offers “log in with your Dr Green wallet” as a holder-facing flow (e.g. for a self-serve store provisioning UI), you’d implement the full nonce → sign → JWT flow client-side. This is unusual; most stores use Dr Green’s DAPP UI for this.Situation 2: Staff dashboard with multiple holders
If you operate stores for multiple holders and want a unified ops dashboard, the staff log into your backend, but the holder data is fetched per-holder using their stored API keys. You don’t authenticate as the holder — you have their long-lived API key pair.Token lifetime and refresh
🔒 JWT lifetime and refresh-token mechanics are not yet captured live. Standard NestJS Passport JWT defaults are typically 1h–24h, with no refresh by default. If your store needs to maintain a long-lived JWT session (rather than just using API keys), confirm the lifetime and refresh policy with the Dr Green backend team. For store-to-API integrations, don’t bother with JWTs — use the API-key + signature auth on every request. It’s simpler and doesn’t expire.Email verification (/auth/verifyEmail, /auth/resendEmail)
These endpoints power the email-verification flow for staff/admin sign-ups (not holders, who authenticate via wallet). Not relevant to store builders. They’re listed here only for completeness against the live OpenAPI spec.
Common patterns
”Are you sure I shouldn’t just use the JWT in my store?”
No. JWTs:- Expire (you’d need to handle refresh)
- Are bearer tokens (anyone with the JWT is the user)
- Aren’t designed for long-lived service-to-service auth
- Don’t expire
- Each request is signed individually (compromise of one signature doesn’t compromise the key — though compromise of the secret key does, of course)
- Map cleanly to per-NFT scoping
”Can my store sign in on the holder’s behalf to call JWT-only endpoints like /dapp/users/nfts?”
Technically yes (if you have the holder’s wallet private key, which you should NOT have), but no in practice. JWT-only endpoints (/user/me, /dapp/users/nfts) are not part of the store-builder integration surface. Ask the holder to use the DAPP UI for those operations. See NFTs for the implications.
See also
- Authentication — request signing for
/dapp/*endpoints - Keys — managing API key pairs after sign-in
- NFTs — JWT-only NFT endpoints