feat: age verification with an ID document (Didit), and closed registration
Age: a Didit provider behind the vendor-neutral age interface. A person verifies once (ID document, passive liveness, face match) and all their linked IMVU accounts count as adult. Webhooks are checked against Didit's signatures; only "over 18" is kept. A later answer replaces an earlier one (an approval taken back is revoked). Checks are limited: one unfinished check per person, 3 in 30 days, none once verified, and a monthly cap (DIDIT_MONTHLY_LIMIT, default 30: Didit's free plan is $10 of credit a month and a check costs $0.30). The Account page gets an Age Verification card. Registration: open or closed, an admin's setting in the console (default from REGISTRATION). Closed: new accounts can only sign in until a moderator approves them (or declines, deleting the account); the website shows them a waiting page and the API treats them as signed out. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
86ebe976ba
commit
c75a4c9afc
28 files changed
+3260
-89
No files matched your search
+22
-5
@@ -100,6 +100,9 @@ age, not verified) and `tagline`.
|
||||
- **Switching accounts in the client**: the proxy sees which IMVU account logs in and tells the hub. Not linked:
|
||||
offer to link. Linked to another hub account: no community features that session.
|
||||
- **Bans** apply to the person, so all linked accounts.
|
||||
- **Registration** is open or closed, an admin's setting in the console (default from `REGISTRATION`; staging is
|
||||
meant to be closed, for testers only). Closed: anyone can sign up, but the account can only sign in until a
|
||||
moderator approves it (or declines it, deleting it); the hub treats it as signed out everywhere else.
|
||||
|
||||
## Age (**Decided**: free, several providers, vendor-neutral)
|
||||
|
||||
@@ -112,8 +115,11 @@ No payment for verification (adult content rules out mainstream merchants of rec
|
||||
2. **Phone wallets** (planned): a government ID in Google Wallet, Apple Wallet or an EU age-verification wallet,
|
||||
asked for "age over 18" only, through the browser's Digital Credentials API. Free for the hub; no documents or
|
||||
birth date reach it. Scope: the person.
|
||||
3. **ID document and selfie** (planned): Didit's hosted check, within its free monthly allowance. Scope: the person
|
||||
(the liveness step stops someone using another person's ID).
|
||||
3. **ID document and selfie** (live, `didit`): Didit's hosted check: ID document $0.15, passive liveness $0.10 and
|
||||
face match $0.05, so $0.30 a check, paid from the free plan's $10 of credit a month (since 2026-11-01; the 500
|
||||
free checks a month are gone), so about 30 a month unless topped up. Scope: the person (liveness and face match
|
||||
stop someone using another person's ID). Over 18 is worked out from the age Didit reads off the document;
|
||||
nothing else is kept. With so few checks, phone wallets (free) should become the main way.
|
||||
|
||||
### How it's built
|
||||
|
||||
@@ -128,14 +134,25 @@ No payment for verification (adult content rules out mainstream merchants of rec
|
||||
webhook), and optionally `recheck` (for providers whose answer can change, like IMVU). Which ones run is
|
||||
configuration (`AGE_PROVIDERS`), with each provider's keys in its own settings. Adding or replacing a vendor is
|
||||
one new adapter; nothing else changes.
|
||||
- Webhooks arrive at `/api/v1/age/webhook/<provider>` and each provider checks its own signature.
|
||||
- Webhooks arrive at `/api/v1/age/webhook/<provider>` and each provider checks its own signature. The provider's
|
||||
latest answer stands: one taken back after approval (say, by a manual review) becomes `revoked`.
|
||||
- **Limits** on checks of a person, for every provider: one unfinished check at a time (starting again gives the
|
||||
same one), at most 3 started in 30 days, none once verified, and a provider's monthly cap (`monthlyLimit`; Didit's
|
||||
`DIDIT_MONTHLY_LIMIT`, default 30), counted from the checks started this month (UTC).
|
||||
- People are sent back only to the hub's website (`returnURL` is a path on it, or an address on `WEB_URL`).
|
||||
- Enforced at three points: catalogs (adult files need an adult token), the hub (adult items left out of room
|
||||
channels for viewers who aren't adult and opted in), and the viewer's proxy.
|
||||
|
||||
### Setting up Didit
|
||||
|
||||
In Didit's console (business.didit.me): an application; a KYC workflow with ID verification, passive liveness and
|
||||
face match only (no IP analysis, AML or proof of address, which cost extra; no white label, $0.10 a session more);
|
||||
an API key; and a webhook destination
|
||||
`<API_URL>/api/v1/age/webhook/didit` with its secret. Then the API's environment: `AGE_PROVIDERS=imvu,didit`,
|
||||
`DIDIT_API_KEY`, `DIDIT_WORKFLOW_ID`, `DIDIT_WEBHOOK_SECRET`. Use the sandbox application on staging.
|
||||
|
||||
### To add the planned providers
|
||||
|
||||
- Didit: an account, an API key and webhook secret, and a workflow set to ID document plus liveness, returning
|
||||
only "over 18". Confirm its free monthly allowance covers age checks.
|
||||
- Wallets: Google's Digital Credentials verifier registration (free), and an `age_over_18` request (OpenID4VP,
|
||||
mdoc); Apple and the EU wallet through the same browser API where supported.
|
||||
|
||||
|
||||
Reference in new issue
Block a user