Identity Verification
Identity Verification lets Business Actions declare how much trust they need. Qefro first resolves identity from the channel, then asks the organization's Customer Access Service whether the customer may perform the action.
Qefro is not a customer Identity Provider — it never sends or verifies OTP.
Architecture
Channel → Identity Resolver → Resolved Identity → Organization Customer Access Service → Authentication Decision → Authentication Context (optional) → Business Tool
Authentication requirements
| Requirement | Meaning |
|---|---|
public | Anyone can execute |
verified_channel | Requires channel-verified identity (WhatsApp phone, website session, etc.) |
organization_challenge | Requires the organization's Customer Access Service |
Configure on each Business Action:
{ "required_auth_level": "verified_channel" }
Customer authentication is configured under Organization → Customer Access Service, not on individual Business Tools.
Design philosophy
- Do not force OTP or login unless the organization sets
organization_challenge. - WhatsApp Meta-verified phone is verified channel identity — no OTP for
verified_channel. - Website Widget JWT / session from
identify()is verified channel identity — no OTP forverified_channel. - Qefro orchestrates organization challenges; your systems remain the authority for access to your APIs (see Identity Forwarding).
Channel identity
| Channel | Verified when | Identity type |
|---|---|---|
| Meta-verified phone present | phone_number | |
| Website Widget | Host JWT or session via identify() | jwt / session |
| Internal Portal | Employee login (tools blocked in V1) | — |
If a tool requires verified_channel and the channel has no verified identity, the runtime returns CHANNEL_IDENTITY_REQUIRED (widget: ask the customer to sign in on your site). Qefro does not start OTP.
Organization challenge
Only when:
{ "required_auth_level": "organization_challenge" }
Qefro calls your Customer Access Service (POST /auth/evaluate) with the resolved identity and Business Action. Your service may return authenticated, challenge_required (OTP / login URL), denied, or customer_not_found.
When a challenge is required, Qefro relays your message to the customer. When they reply, Qefro forwards the reply to your Access API — your organization verifies it. Qefro never validates OTP codes.
A valid Authentication Context from your service is reused until it expires.
WhatsApp — order status (verified channel)
verified_channel on WhatsApp
- User messages — Where is my order? Meta-verified phone → verified_channel.
- Policy check — Tool requires verified_channel → Allow immediately.
- Execute — Business Tool runs with X-Qefro-* headers. No organization challenge.
WhatsApp — download invoice (organization challenge)
organization_challenge on WhatsApp
- User messages — Download my invoice (phone already verified).
- Access API — Qefro POSTs resolved identity + business_action to your Customer Access Service.
- Challenge — Your service sends OTP / asks for login; Qefro relays the message.
- User replies — Qefro forwards the reply; your service verifies and returns a credential.
- Execute — Runtime injects Authentication Context into the Business Tool request.
Phone mappings
Local table (Admin API) for enriching WhatsApp identity:
PUT /api/v1/workspaces/:id/phone-mappings— upsert{ phone, customer_id?, email?, display_name? }GET /api/v1/workspaces/:id/phone-mappingsDELETE /api/v1/workspaces/:id/phone-mappings/:id
Widget endpoints
identify()JWT/session counts asverified_channelPOST /api/v1/widget/identity/challengeand…/verifyforward to your Customer Access Service (Qefro does not send or verify OTP)
Identity forwarding
Outbound Business Tool requests receive:
| Header | Example |
|---|---|
X-Qefro-User-ID | customer / user id |
X-Qefro-Organization | tenant UUID |
X-Qefro-Authentication-Level | public / verified_channel / organization_challenge |
X-Qefro-Channel | whatsapp / widget / portal |
X-Qefro-Phone | E.164 when known |
Plus org-issued Bearer / JWT / Cookie credentials when your Access API returns them. Tokens are never sent to the LLM.