Confirm that a user controls a phone number. The API delivers a one-time challenge over SMS or a voice call; your code starts the verification and reports back the code the user supplied.
Three packages. Install the one that matches where your code runs.
| Package | Install it in | Gives you |
|---|---|---|
@didww/verification-core |
any JavaScript runtime | the client, the wire types, basic and public auth. No runtime dependencies. |
@didww/verification-node |
a Node.js server | signed application auth, and the inbound callback gate that allows or denies a verification. |
@didww/verification-react-native |
a React Native app | useVerification(), and Android SMS auto-fill. |
verification-node and verification-react-native both depend on verification-core, so
installing either brings it with it.
| Mode | Credential | Where it may be used | Package |
|---|---|---|---|
application |
key + secret, HMAC-signed per request | server only — the secret must never ship in an app | @didww/verification-node |
basic |
key + secret sent verbatim | server only | @didww/verification-core |
public |
key only | a mobile or browser client | @didww/verification-core |
basic and application both prove possession of the secret, so both are confined to a server:
anything shipped to a device is recoverable from the bundle, and application is the only one that
never puts the secret on the wire at all. public sends a key that is an identifier rather than a
secret, which is why it is safe on a device — and why it is not, on its own, authorisation. A start
made with public or basic is put to your own server first, over the
callback gate; a start signed with
application is already trusted and is never gated.
So a mobile app either talks to the API directly with public auth and answers the callback from
your backend, or proxies every call through your backend, which uses application.
Each application also carries a minimum scheme, ranked public < basic < application. A
request below it is rejected with 401.
import { VerificationClient, basicAuth } from '@didww/verification-core';
const client = new VerificationClient({
auth: basicAuth(process.env.DIDWW_KEY!, process.env.DIDWW_SECRET!),
environment: 'sandbox',
});
const started = await client.startVerification({
destination: '+12025550143',
deliveryMethod: 'sms',
});
const result = await client.reportVerification(started.id, {
deliveryMethod: 'sms',
code: '123456',
});
console.log(result.status); // 'verified' | 'failed' | 'expired' | 'denied' | 'pending'The sandbox environment (environment: 'sandbox') sends no real SMS and places no real calls. Only
the reserved test numbers give a predefined result, such as delivered, failed or expired, and a
delivered one has a fixed code. Any other number is never delivered to, and its verification ends as
failed. The test numbers, their outcomes and the code to submit are listed in
Testing on sandbox.
Runnable, in examples/:
mock-api— an in-memory stand-in for the API, so the rest runs with no credentials and no publicly reachable URL.npm start --prefix examples/mock-apinode-server— an Express backend: a start/report proxy over signedapplicationauth, and the inbound callback gate.npm start --prefix examples/node-serverexpo-app— an Expo app overuseVerification(), with a branch for every state and the app hash read off the running build.npm start --prefix examples/expo-app
Other SDKs for the same API, each in its own repository:
- Android SDK — Kotlin
- iOS SDK — Swift
- Ruby SDK
See CONTRIBUTING.md.
MIT — see LICENSE.