Documentation Index
Fetch the complete documentation index at: https://docs.dr.green/llms.txt
Use this file to discover all available pages before exploring further.
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 resulting apiKey + secretKey pair 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
[Holder's browser]
│
│ 1. POST /api/v1/auth/nonce → receives a nonce
│ 2. Browser prompts wallet to sign:
│ message = "Welcome to Dr Green!\n\nNonce: <nonce>"
│ (SIWE-style — the exact message format is set by the DAPP UI)
│ 3. POST /api/v1/auth/dapp/signIn { walletAddress, signature, nonce }
│ → receives a JWT
│ 4. JWT is now used for /dapp/* (UI flows) and /keys (key management)
│ 5. POST /keys (JWT auth)
│ → receives { apiKey, secretKey } pair
│ 6. Holder hands the pair to a store developer (you)
│
[Store backend]
│
│ 7. From here onwards, store uses { apiKey, secretKey } on every /dapp/* call
│ (no JWT needed)
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/signIn is for Dr Green admin/staff accounts (SUPERADMIN, ADMIN, SUBADMIN, MANAGER roles). Holders (USER role) use /auth/dapp/signIn instead. 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
{
"walletAddress": "0x553374bd6e81f952821e37f4b8e208a81164fb2e"
}
| Field | Type | Required | Notes |
|---|
walletAddress | string | ✅ | Lowercased Ethereum address |
No request signing required
This is an unauthenticated endpoint. No x-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
walletAddress and only valid for that address’s signature.
POST /auth/dapp/signIn — wallet sign-in
Exchange a wallet-signed nonce for a JWT.
Request body
Per SignInDto:
{
"walletAddress": "0x553374bd6e81f952821e37f4b8e208a81164fb2e",
"nonce": "<from /auth/nonce>",
"signature": "0x...<wallet signature of the message>"
}
| 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:
{
"success": true,
"statusCode": 201,
"message": "Success",
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": {
"id": "...",
"walletAddress": "0x...",
"role": "USER",
"primaryNft": { "tokenId": 56 }
}
}
}
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:
Welcome to Dr Green!
Sign this message to authenticate.
Nonce: <nonce-from-/auth/nonce>
🔒 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:
- 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
For most store integrations, option 1 is the right call — let Dr Green handle wallet auth, and consume the resulting keys.
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
API keys with per-request signatures are the right primitive for a store backend. They:
- 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