Skip to main content

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

MethodPathAuthDescription
POST/auth/nonceNoneGenerate a nonce for wallet signing
POST/auth/dapp/signInNoneExchange a wallet signature for a JWT
POST/auth/signInNoneAdmin / staff login (NOT for holders or stores)
GET/auth/verifyEmailNoneEmail verification callback (out of band)
GET/auth/resendEmailNoneRe-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"
}
FieldTypeRequiredNotes
walletAddressstringLowercased 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>"
}
FieldTypeRequiredNotes
walletAddressstringSame as the nonce was issued for
noncestringThe exact value returned by /auth/nonce
signaturestringThe 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:
  1. Direct the holder to the DAPP UI to authenticate and generate keys (recommended), or
  2. 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