# Vonvon: full public documentation corpus (en)
- Concise index: https://vonvon.id/en/llms.txt
- Documentation hub: https://vonvon.id/docs
- Published pages: 44
## Canonical aliases
- `/docs/oidc` -> `/oidc-oauth`
- `/docs/oauth` -> `/oidc-oauth`
- `/docs/sso` -> `/enterprise-sso`
## Pages
# Build identity at the edge, without giving up control
> Vonvon brings Hosted Auth, OIDC, organizations, enterprise federation, directory sync, and SDKs into one MIT-licensed platform running on Cloudflare Workers.
Locale: en
Canonical: https://vonvon.id/
Markdown: https://vonvon.id/index.md
Source: https://vonvon.id/index.mdx
Vonvon brings Hosted Auth, OIDC, organizations, enterprise federation, directory sync, and SDKs into one MIT-licensed platform running on Cloudflare Workers.
## Three focused Workers. One identity platform.
Public content and management stay binding-free. Identity state, protocols, and policy remain in Core.
- **Site:** Product, documentation, search, and agent-readable content
- **Console:** Organization and instance management UI
- **Core:** Hosted Auth, protocols, APIs, data, and asynchronous work
## One control plane from sign-in to enterprise access
Use the complete platform or adopt the protocol, UI, and SDK layers that fit your architecture.
### Authentication and account
Hosted sign-in, passkeys, password, MFA, session management, consent, and account self-service share one tenant-aware Core.
### Organizations and access
Model organizations, OrgUnits, projects, roles, grants, approval policies, and access requests without creating a separate admin tenant.
### Federation and provisioning
Connect inbound SAML and OIDC, downstream SaaS SSO, SCIM, directory sync, and domain discovery behind explicit policy boundaries.
### Protocols and developer experience
Ship OIDC and OAuth flows, Management APIs, webhooks, framework SDKs, localized docs, and networkless token verification from one repository.
## Production where proven, local where not
First-party Hosted Auth, Console, and Management API paths have production evidence on vonvon.id. Enterprise IdP, downstream SaaS, social OAuth, and SMS or WhatsApp claims stay non-production-supported until a real L4 row exists for that path.
## Open source, inspectable, and self-hostable
The MIT-licensed repository includes the complete feature set. Security posture and project governance remain visible through OpenSSF and the public source.
# Vonvon Identity Platform
> Vonvon brings Hosted Auth, passkeys, OIDC and OAuth, organizations, enterprise federation, SCIM, and SDKs into one identity platform built for Cloudflare.
Locale: en
Canonical: https://vonvon.id/docs
Markdown: https://vonvon.id/docs/index.md
Source: https://vonvon.id/docs/index.mdx
Open source identity platform
Vonvon brings Hosted Auth, passkeys, OIDC and OAuth, organizations, enterprise federation, SCIM, and SDKs into one identity platform built for Cloudflare.
## One platform for identity
Vonvon handles sign-in, authorization, organization membership, enterprise connections, and user lifecycle from one identity core. Applications use standards-based endpoints while teams manage the instance and every organization from one Console.
Run the same MIT-licensed codebase in single-tenant or multi-tenant mode on your Cloudflare account. Self-hosting includes every feature with no license check or separate edition.
Vonvon is pre-1.0 and not production-ready. The documentation distinguishes local implementation evidence from real provider and SaaS verification.
## What Vonvon includes
- Hosted Auth, passkeys, passwords, magic links, social sign-in, MFA, recovery, consent, and account self-service.
- OIDC and OAuth 2.0, token issuance, discovery, JWKS, organizations, projects, applications, roles, and permissions.
- Inbound enterprise SAML and OIDC, SCIM user and group provisioning, webhooks, audit records, and management APIs.
- Browser, server, web framework, mobile, and desktop SDKs for integrating applications across the stack.
## Explore Vonvon
### Product and setup
- [Getting started](/getting-started)
Connect an application to Vonvon with OIDC discovery and Hosted Auth.
- [Hosted Auth](/hosted-auth)
Configure the unified sign-in and user creation flow.
- [Organizations](/organizations)
Model Organization, OrgUnit, project, and access approval boundaries.
- [Branding](/branding)
Manage the seven stored organization branding fields exposed by the Management API. Hosted Auth runtime application and custom CSS are not shipped.
- [Self-hosting](/self-hosting)
Deploy Vonvon as three isolated Workers on your Cloudflare account, with the complete data, queue, consistency, email, routing, and production-control inventory.
### Identity protocols
- [OIDC and OAuth](/oidc-oauth)
Discovery, authorization, token, logout, and OAuth extension endpoints.
- [Enterprise SSO](/enterprise-sso)
Configure upstream enterprise IdPs and track downstream SaaS SSO boundaries without overstating production support.
- [Social login](/social-login)
Configure social OAuth providers while keeping provider-ready separate from production support.
- [SCIM API reference](/scim)
SCIM 2.0 endpoint contract for provisioning users and groups into Vonvon.
- [SAML SSO](/saml)
Connect enterprise identity providers using SAML 2.0.
### APIs and operations
- [Management API](/management-api)
Use scoped API keys to manage organization resources from your backend.
- [Webhooks](/webhooks)
Subscribe to implemented user, organization, membership, invitation, and SAML certificate events through signed HTTP deliveries.
### SDK overview
- [SDKs](/sdks)
TypeScript packages and locally verified native SDKs for server, web, mobile, and desktop.
### Server SDKs
- [@vonvon-kit/backend](/sdks/backend)
Networkless JWT verification, request authentication, and webhook signature validation for edge and server runtimes.
- [sdk/go](/sdks/go)
Go server SDK for networkless JWT verification, request authentication, and webhook signature validation.
- [sdk/rust](/sdks/rust)
Async Rust server SDK for networkless JWT verification, request authentication, and webhook signature validation.
- [sdk/python](/sdks/python)
Async Python server SDK for networkless JWT verification, request authentication, and webhook signature validation.
- [sdk/ruby](/sdks/ruby)
Ruby server SDK for networkless JWT verification, Rack/Rails request authentication, and webhook signature validation.
- [sdk/php](/sdks/php)
PHP 8.1+ server SDK for networkless JWT verification, PSR-7 request authentication, and webhook signature validation.
- [sdk/java](/sdks/java)
Java 17+ server SDK for networkless JWT verification, HTTP request authentication, and webhook signature validation.
- [sdk/dotnet](/sdks/dotnet)
.NET 8 server SDK for networkless JWT verification, ASP.NET Core request authentication, and webhook signature validation.
### Web SDKs
- [@vonvon-kit/core](/sdks/core)
Browser client for session state, short-lived JWT access, and Management API helpers.
- [@vonvon-kit/react](/sdks/react)
React 19 provider, hooks, control components, and hosted UI building blocks for customer applications.
- [@vonvon-kit/nextjs](/sdks/nextjs)
Next.js middleware, App Router and Pages Router server helpers, plus React SDK re-exports.
- [@vonvon-kit/vue](/sdks/vue)
Vue 3 plugin, composables, and headless components on top of @vonvon-kit/core.
- [@vonvon-kit/nuxt](/sdks/nuxt)
Nuxt 3 module with H3/Nitro server middleware and auto-imported Vue composables for SSR and full-stack apps.
- [@vonvon-kit/svelte](/sdks/svelte)
Svelte 5 reactive stores and SvelteKit server hook for client and SSR authentication.
- [@vonvon-kit/solid](/sdks/solid)
SolidJS context provider, signal-based auth primitives, and headless components on top of @vonvon-kit/core.
- [@vonvon-kit/angular](/sdks/angular)
Angular 17+ standalone provider, RxJS service, functional route guards, and standalone components on top of @vonvon-kit/core.
- [@vonvon-kit/astro](/sdks/astro)
Astro integration with SSR middleware, server helpers, and island client singleton for static and server-rendered Astro sites.
- [@vonvon-kit/remix](/sdks/remix)
Remix loader and action server helpers, cookie session storage, and OAuth callback handler with React SDK re-exports.
### Mobile SDKs
- [@vonvon-kit/react-native](/sdks/react-native)
React Native provider and hooks for Hosted Auth redirect, PKCE S256, deep-link callback, and secure token storage adapters.
- [@vonvon-kit/expo](/sdks/expo)
Expo SecureStore and WebBrowser adapters for @vonvon-kit/react-native plus an Expo Router route guard hook.
- [sdk/ios](/sdks/ios)
Swift SDK for iOS and macOS using ASWebAuthenticationSession, PKCE S256 authorization code flow, and Keychain token storage.
- [sdk/android](/sdks/android)
Kotlin SDK for Android using Chrome Custom Tabs, PKCE S256 authorization code flow, and Keystore-backed EncryptedSharedPreferences token storage.
- [sdk/flutter](/sdks/flutter)
Dart / Flutter SDK for iOS, Android, and desktop using flutter\_web\_auth\_2, PKCE S256 authorization code flow, and flutter\_secure\_storage token persistence.
### Desktop SDKs
- [@vonvon-kit/electron](/sdks/electron)
Electron SDK with main process PKCE flow, contextBridge preload, OS keychain token storage, and loopback or custom-scheme callback strategies.
- [@vonvon-kit/tauri](/sdks/tauri)
Tauri v2 desktop SDK with PKCE S256 flow, deeplink callback handler, OS keychain adapter, and Rust plugin template.
- [sdk/macos](/sdks/macos)
Swift SDK for macOS using ASWebAuthenticationSession, PKCE S256 authorization code flow, and Keychain token storage. Shares the implementation pattern with sdk/ios.
- [sdk/windows](/sdks/windows)
C# / .NET SDK for WinUI 3 applications using WebView2 for authorization, PKCE S256, and DPAPI-protected IsolatedStorage for token persistence.
- [sdk/linux](/sdks/linux)
Rust SDK for Linux desktop using xdg-open for browser launch, loopback TCP for the authorization callback, PKCE S256, and freedesktop.org Secret Service token storage.
# Getting started
> Connect an application to Vonvon with OIDC discovery and Hosted Auth.
Locale: en
Canonical: https://vonvon.id/getting-started
Markdown: https://vonvon.id/getting-started/index.md
Source: https://vonvon.id/getting-started/index.mdx
## Base URLs
Vonvon is an identity provider. The instance domain is the OIDC issuer, API base URL, Hosted Auth base URL, and console base URL. Organizations provide policy, branding, membership, and resource isolation.
Start by reading `/.well-known/openid-configuration` from the instance domain. The discovery document gives your app the authorization, token, userinfo, logout, and JWKS endpoints for that issuer.
| Surface | Path | Use |
| --- | --- | --- |
| OIDC discovery | `/.well-known/openid-configuration` | Read issuer metadata before configuring a relying party. |
| Authorization | `/authorize` | Redirect users to the unified Hosted Auth flow. |
| Token | `/token` | Exchange an authorization code or refresh token. |
| Userinfo | `/userinfo` | Read claims for a valid access token. |
| Management API | `/v1/*` | Manage organization resources from your backend. |
## Minimum integration
- Create an OIDC application and register exact redirect URI values.
- Use authorization code flow with PKCE S256 for browser and native clients.
- Validate ID tokens and access tokens against the issuer and JWKS URI.
- Store refresh tokens server side or in a secure native credential store.
## Authorization request
```mermaid
sequenceDiagram
participant Browser
participant RP
participant Vonvon
RP->>Browser: /authorize + PKCE S256
Browser->>Vonvon: /authorize + PKCE S256
Vonvon->>Browser: /sign-in
Browser->>Vonvon: WebAuthn / SSO
Vonvon->>Browser: code
Browser->>RP: code
RP->>Vonvon: /token + PKCE S256
Vonvon->>RP: ID token + access token
```
```js
const authorizeUrl = new URL('https://vonvon.id/authorize')
authorizeUrl.searchParams.set('client_id', clientId)
authorizeUrl.searchParams.set('redirect_uri', redirectUri)
authorizeUrl.searchParams.set('response_type', 'code')
authorizeUrl.searchParams.set('scope', 'openid profile email')
authorizeUrl.searchParams.set('code_challenge', codeChallenge)
authorizeUrl.searchParams.set('code_challenge_method', 'S256')
```
# Hosted Auth
> Configure the unified sign-in and user creation flow.
Locale: en
Canonical: https://vonvon.id/hosted-auth
Markdown: https://vonvon.id/hosted-auth/index.md
Source: https://vonvon.id/hosted-auth/index.mdx
## Unified flow
Vonvon does not expose separate end-user registration and login products. Hosted Auth starts from the same identifier step and decides login or user creation from organization policy and account state. A guest or credential sign-up with intent=sign-up then creates a top-level Tenant with an Email, Organization name, and URL slug. A guest Email stays pending without reserving an account address; the new owner can read Console data, and verifies that Email before the first business change. The same Email in another Tenant remains a separate account.
Bootstrap defaults enable email magic link and email OTP only. Password, WhatsApp OTP, SMS OTP, passkey, social OAuth, and enterprise SSO stay hidden until the organization policy and required credentials enable them.
Passwordless email magic-link and OTP requests freeze the sign-up intent, server-owned continuation, application client, and invitation row ID when the challenge is created. Social OAuth invitation authorization likewise validates the raw capability before redirecting upstream, persists only the invitation row ID in its one-time state, and ignores caller-owned token routes on callback. Verification cannot rewrite those fields. Raw invitation capabilities are never stored in these flow contexts; when MFA interrupts acceptance, Vonvon uses a short-lived signed continuation bound to the Tenant, User, Session, and invitation.
```mermaid
flowchart TD
Browser --> authorize["/authorize"]
authorize --> signIn["/sign-in"]
signIn --> config["/auth/config"]
config --> methods["WebAuthn / Password / OTP / SSO"]
config --> signup["guest or intent=sign-up"]
signup --> createOrg["/create-organization"]
createOrg --> readOnly["Console reads"]
readOnly --> verifyEmail["Verify Email"]
verifyEmail --> mutations["Business mutations"]
methods --> code["code"]
methods --> mfa["/auth/mfa/passkey/*"]
mfa --> code
```
## Configuration endpoint
`GET /auth/config` returns the public Hosted Auth configuration for the organization. Provider secrets and disabled providers are not returned to the browser.
| Method | Displayed when |
| --- | --- |
| Magic link | Enabled and allowed for login or user creation. |
| Email OTP | Enabled and allowed for login or user creation. |
| Phone OTP | WhatsApp or SMS provider is configured, enabled, and allowed for login or user creation. |
| Password | Password policy enables login or user creation. |
| Social OAuth | Provider is enabled, credentials exist, and policy allows the action. |
| Inbound enterprise SSO | Domain discovery matches a verified organization domain. |
## Identifier policy
- Organizations can require email identifiers, username identifiers, or both.
- Allowed and blocked email domain lists apply before user creation.
- Force SSO hides local methods when an enterprise connection is required.
## WebAuthn and passkey boundaries
- Passkey sign-in is primary AAL2 authentication. Password or OTP sessions can complete MFA through `/auth/mfa/passkey/*` with user verification required.
- Organization policy `attestationMode` selects none, indirect, or direct enterprise attestation during passkey registration.
- WebAuthn credential parameters advertise ES256, RS256, and EdDSA. Syncable passkeys remain AAL2 even after MFA.
- `urn:vonvon:aal3` is not currently issued. WebAuthn UV and BE/BS flags do not prove the non-exportable hardware key required by NIST; AAL3 requests fail explicitly and the current maximum mapping is AAL2.
# Organizations
> Model Organization, OrgUnit, project, and access approval boundaries.
Locale: en
Canonical: https://vonvon.id/organizations
Markdown: https://vonvon.id/organizations/index.md
Source: https://vonvon.id/organizations/index.mdx
## Organization hierarchy
An Instance contains top-level Organizations. An Organization can contain one level of SubOrg; each organization remains a policy, membership, branding, RBAC, and isolation boundary.
An OrgUnit is a department or team inside one Organization. It never changes TenantContext, issuer, token claims, or the one-level SubOrg limit.
- OrgUnit trees support a maximum depth of eight.
- Each member can have one primary OrgUnit and additional placements.
- The nearest active manager in the OrgUnit ancestor chain is the first access-request approver candidate.
## Projects and access policy
Projects group applications and authorization roles. The per-project `access_policy` controls only same-organization users without an effective UserGrant; cross-organization ProjectGrant authorization is unaffected.
| Project policy | Same-organization behavior | Self-service path |
| --- | --- | --- |
| Open | Allowed without a UserGrant. | No access request is needed. |
| Restricted | Denied; an administrator grants access directly. | No self-service request is available. |
| Approval required | Denied until an AccessRequest is approved. | The user submits an access request. |
## Access request lifecycle
AccessRequest moves from `pending` to `approved`, `denied`, `cancelled`, or `expired`. Every outcome is terminal, and pending requests expire lazily after 14 days.
Approval creates a traceable UserGrant in the same transaction. The requester cannot approve their own request; resolution falls through from the OrgUnit manager to project and organization managers.
| Method | Path | Purpose | Required scope |
| --- | --- | --- | --- |
| `GET, POST` | `/auth/access-requests` | Create and list the current user's requests. | `session` |
| `POST` | `/auth/access-requests/:id/cancel` | Cancel the current user's pending request. | `session` |
| `GET` | `/auth/access-approvals` | List requests awaiting the current user's approval. | `session` |
| `POST` | `/auth/access-approvals/:id/{approve\|deny}` | Approve or deny a pending request assigned to the current user. | `session` |
| `GET` | `/v1/organizations/:orgId/access-requests` | List requests inside one organization. | `access-requests:read` |
| `GET` | `/v1/organizations/:orgId/units` | Read the organization unit tree. | `org-units:read` |
| `POST, PATCH, DELETE, PUT` | `/v1/organizations/:orgId/units/*` | Create, update, move, archive, and manage members of units. | `org-units:write` |
## Security boundaries
- Every OrgUnit and AccessRequest query is scoped by `tenant_id` and `org_id`. Cross-organization or cross-tenant identifiers return 404 without revealing existence.
- Membership and project access are separate: invitations join an Organization, while AccessRequest grants an existing active member access to one Project.
- SCIM provisions users and memberships but does not map directory groups to OrgUnits or Project roles in the current implementation.
- The Management API uses cursor pagination and shared API-key or organization-manager guards. It does not reuse end-user business routes.
# OIDC and OAuth
> Discovery, authorization, token, logout, and OAuth extension endpoints.
Locale: en
Canonical: https://vonvon.id/oidc-oauth
Markdown: https://vonvon.id/oidc-oauth/index.md
Source: https://vonvon.id/oidc-oauth/index.mdx
## Core endpoints
| Endpoint | Description |
| --- | --- |
| `/.well-known/openid-configuration` | OIDC discovery for the current issuer. |
| `/.well-known/oauth-protected-resource` | OAuth protected resource metadata for Vonvon-hosted resource endpoints. |
| `/jwks` | Instance public signing keys with active and rotating kids. |
| `/authorize` | Authorization endpoint with PKCE, state, nonce, PAR, and Hosted Auth handoff. |
| `/par` | Pushed Authorization Requests with one-time request\_uri values. |
| `/token` | Authorization code, refresh token, client credentials, device code, and token exchange. |
| `/userinfo` | Bearer or DPoP access token user claims. |
| `/end_session` | RP-initiated logout with registered post logout redirects. |
## Protocol requirements
- PKCE uses S256. Plain PKCE is rejected.
- Redirect URI matching is exact. Wildcards are not accepted.
- Authorization codes are one-time use.
- Refresh tokens rotate on every use and replay revokes the token family.
- DPoP-bound clients must present a valid DPoP proof for token and resource calls. Authorization request `dpop_jkt` is bound to authorization code exchange.
## Support levels
| Level | OAuth and OIDC features |
| --- | --- |
| Implemented | Authorization code, PKCE S256, refresh rotation, PAR, DPoP proof and `dpop_jkt` binding, dynamic client registration, ID tokens, userinfo, hybrid response types, signed JAR request objects, signed JARM responses, RAR `resource_access` authorization details, token exchange, mTLS client authentication, front-channel and back-channel logout, Device Flow, Session Management, CIBA, Browser-Based Apps profile gates, and FAPI 2.0 profile gates. |
| Minimal implementation | OpenID Federation exposes entity metadata and a registration boundary only. Trust-chain resolution, trust anchors, policy processing, and production interoperability are not implemented. |
| Planned | Shared Signals, CAEP, RISC, GNAP, UMA, HEART, OpenID4VP, and OpenID4VCI expose reserved routes that return explicit 501 errors. They are not protocol implementations. |
| Production evidence | Local implementation and conformance gates are not production certification. Downstream SaaS OIDC uses the generic OIDC baseline, but each SaaS integration still requires real external L4 evidence. |
| Deprecated or not supported | Implicit flow, password grant, plain PKCE, and wildcard redirects. |
## Role boundaries
| Vonvon role | Current public status |
| --- | --- |
| OIDC / OAuth identity provider for customer applications | Implemented in local and Worker routes with authorization code, PKCE S256, PAR, DPoP, JAR, JARM, RAR, discovery, JWKS, token, userinfo, introspection, and revocation coverage. |
| Upstream enterprise OIDC relying party | Provider-ready for enterprise connections. Production support requires a real IdP configuration and callback L4. |
| Social OAuth relying party | Provider-ready for GitHub, Google, Microsoft account, and Apple. See Social login for provider-specific boundaries. |
| Downstream SaaS OIDC identity provider | Generic OIDC baseline is available locally. SaaS-specific app templates and real SaaS L4 are still required before production support claims. |
## Client types
| Client | Recommended flow |
| --- | --- |
| Web application | Authorization code with server side token exchange. |
| SPA | Authorization code with PKCE S256. |
| Native app | Authorization code with PKCE S256 and claimed redirects. |
| Machine to machine | Client credentials with scoped access. |
## Guarded or minimal OAuth and OIDC extensions
| Level | Status |
| --- | --- |
| Assertion grants | JWT bearer and SAML bearer assertion grants are not enabled. Registration rejects assertion grant metadata until a trust root exists. |
| GNAP, UMA, HEART, OpenID4VP, OpenID4VCI | Only negative route and metadata stubs are exposed. Unsupported operations return explicit `501 unsupported_feature`; no functional protocol support is claimed. |
# Enterprise SSO
> Configure upstream enterprise IdPs and track downstream SaaS SSO boundaries without overstating production support.
Locale: en
Canonical: https://vonvon.id/enterprise-sso
Markdown: https://vonvon.id/enterprise-sso/index.md
Source: https://vonvon.id/enterprise-sso/index.mdx
## Two directions
Inbound enterprise SSO means Vonvon acts as the SAML service provider or OIDC relying party for a company IdP. Downstream SaaS SSO means Vonvon acts as the SAML or OIDC identity provider for apps such as Slack, GitHub Enterprise Cloud, Microsoft custom apps, Atlassian, Salesforce, and Zoom.
Both directions are separate evidence lines. A local fake IdP or fake SaaS run verifies the implementation baseline, but only a real external IdP or SaaS admin run can support a production-supported claim.
```mermaid
flowchart LR
IdP -->|SAML / OIDC| vonvonSp["Vonvon SP / RP"]
vonvonIdP["Vonvon IdP"] -->|SAML / OIDC| SaaS
```
## Upstream enterprise IdP status
| Provider | Protocols | Status |
| --- | --- | --- |
| Microsoft Entra ID | SAML, OIDC, SCIM inbound | Provider-ready, missing real IdP L4. |
| Okta | SAML, OIDC, SCIM inbound | Provider-ready, missing real IdP L4. |
| Google Workspace | SAML, OIDC, SCIM inbound | Provider-ready, missing real IdP L4. |
| OneLogin | SAML, OIDC, SCIM inbound | Provider-ready, missing real IdP L4. |
| JumpCloud | SAML, OIDC, SCIM inbound | Provider-ready, missing real IdP L4. |
| PingOne | SAML, OIDC | Provider-ready, missing real IdP L4. |
| PingFederate | SAML, OIDC | Provider-ready, missing real IdP L4. |
| AD FS | SAML, OIDC, WS-Fed legacy baseline | Implemented locally; real AD FS WS-Fed L4 missing. |
| Shibboleth | SAML, OIDC | Provider-ready, missing real IdP L4. |
| Keycloak | SAML, OIDC, LDAP legacy baseline | Implemented locally; native Kerberos bridge is documented-only. |
## Downstream SaaS SSO status
| SaaS | Direction | Status |
| --- | --- | --- |
| Slack | Vonvon as SAML IdP | Provider-ready with local outbound SAML baseline; real Slack admin L4 missing. |
| GitHub Enterprise Cloud | Vonvon as SAML IdP | Provider-ready with local outbound SAML baseline; real GitHub Enterprise L4 missing. |
| Microsoft custom enterprise app | Vonvon as SAML or OIDC IdP | Provider-ready with generic SAML/OIDC baseline; real Entra custom app L4 missing. |
| Atlassian | Vonvon as SAML IdP | Provider-ready with local outbound SAML baseline; real Atlassian admin L4 missing. |
| Salesforce | Vonvon as SAML or OIDC IdP | Provider-ready with generic SAML/OIDC baseline; real Salesforce admin L4 missing. |
| Zoom | Vonvon as SAML or OIDC IdP | Provider-ready with generic SAML/OIDC baseline; real Zoom admin L4 missing. |
## Legacy protocol boundaries
- LDAP direct bind, WS-Federation, SWA password vaulting, header-based SSO, and directory connector framework are implemented locally with fake harness L3. Real AD/LDAP gateway, AD FS WS-Fed, target app vault, and Application Proxy L4 are still missing.
- Linked sign-on, native IWA, and Kerberos termination are not supported.
- SAML Single Logout is implemented and verified locally at L1/L2 for inbound and outbound SAML. The Slack profile is excluded because Slack does not support SLO; real IdP and downstream SaaS L4 evidence remains UNKNOWN.
- Provider-ready rows must not be described as production-supported until real external L4 evidence exists.
# Social login
> Configure social OAuth providers while keeping provider-ready separate from production support.
Locale: en
Canonical: https://vonvon.id/social-login
Markdown: https://vonvon.id/social-login/index.md
Source: https://vonvon.id/social-login/index.mdx
## Provider status
Social login is provider-ready until real provider callback L4 exists. Vonvon has local callback, profile mapping, nonce, policy, and organization gate coverage, but real provider secrets and callbacks are required before production-supported claims.
| Provider | Protocol | Status |
| --- | --- | --- |
| GitHub | OAuth authorization code | Provider-ready, missing real GitHub callback L4. |
| Google | OIDC authorization code | Provider-ready, missing real Google callback L4. |
| Microsoft account | OIDC authorization code | Provider-ready, separate from Microsoft Entra ID. |
| Apple | Sign in with Apple | Provider-ready, missing real Apple web configuration and callback L4. |
## Configuration contract
- Provider credentials are stored as secret references and are never returned to the browser.
- Hosted Auth only displays enabled providers that have credentials and organization policy permission.
- Callbacks verify state, nonce, issuer, audience, and email policy before creating or linking users.
- GitHub social login is separate from GitHub Enterprise Cloud SAML or SCIM.
- Microsoft account login is separate from Microsoft Entra ID enterprise SSO.
# Management API
> Use scoped API keys to manage organization resources from your backend.
Locale: en
Canonical: https://vonvon.id/management-api
Markdown: https://vonvon.id/management-api/index.md
Source: https://vonvon.id/management-api/index.mdx
## Authentication
Management API calls use `Authorization: Bearer sk_live_*` or `Authorization: Bearer sk_test_*`. Keys are scoped to the resolved Tenant. Organization resources additionally verify that the requested Organization belongs to that Tenant.
```shell
curl https://vonvon.id/v1/users \
-H 'Authorization: Bearer sk_live_xxx'
```
## Resources
| Resource | Capabilities | Status |
| --- | --- | --- |
| `/v1/users` | Create, read, update, ban, unban, export, and remove users. | Implemented |
| `/v1/organizations` | Manage organizations, domains, branding, and settings. | Implemented |
| `/v1/organizations/:orgId/memberships` | List, create, update role, and remove members. | Implemented |
| `/v1/organizations/:orgId/invitations` | Create (with bulk limit), revoke, and list invitations. | Implemented |
| `/v1/sessions` | List, get, and revoke user sessions. | Implemented |
| `/v1/applications` | Register OAuth clients, redirect URIs, grants, token policy, and secrets. | Implemented |
| `/v1/connections` | Manage upstream enterprise SSO connections. | Implemented |
| `/v1/directories` | Create SCIM directories and rotate directory tokens. | Implemented |
| `/v1/roles` | Create, read, update, and delete custom roles. | Implemented |
| `/v1/permissions` | Create, read, update, and delete permissions. | Implemented |
| `/v1/project-grants` | Create, list, get, revoke, and delete project grants. | Implemented |
| `/v1/user-grants` | Assign, list, get, revoke, and delete scoped user grants. | Implemented |
| `/v1/organizations/:orgId/domains` | List, create, and remove organization domains. | Implemented |
| `/v1/organizations/:orgId/custom-hostnames` | Create, inspect, refresh, and remove custom hostnames. | Implemented |
| `/v1/organizations/:orgId/audit-events` | Read organization audit events with cursor pagination. | Implemented |
| `/v1/webhooks` | Create, list, update, and delete webhook endpoints. | Implemented |
| `/v1/api-keys` | Create, list, and revoke organization API keys. | Implemented |
| `/v1/organizations/:orgId/scim-targets` | Create, update, sync, and remove outbound SCIM targets. | Implemented |
## Pagination and errors
List endpoints return a data array and cursor metadata. Errors use structured JSON with a stable code, a human-readable message, and optional metadata for field validation.
# Webhooks
> Subscribe to implemented user, organization, membership, invitation, and SAML certificate events through signed HTTP deliveries.
Locale: en
Canonical: https://vonvon.id/webhooks
Markdown: https://vonvon.id/webhooks/index.md
Source: https://vonvon.id/webhooks/index.mdx
## Event naming
Implemented events follow the pattern `
}>
Not signed in}>
Signed in as {auth.userId()}
)
}
```
## createOrganization and createSession
```tsx
const org = createOrganization()
// org() is CreateOrganizationReturn
if (org().isSignedIn) {
console.log(org().organization?.name, org().membership?.role)
const activated = await org().setActive('org_new_id')
if (!activated.ok) throw new Error(activated.error.message)
}
const session = createSession()
if (session().isSignedIn) {
const token = await session().getToken()
if (!token.ok) throw new Error(token.error.message)
// use token.value for backend requests
}
```
## Headless components
```tsx
import { SignInButton, SignOutButton, Protect } from '@vonvon-kit/solid'
// Navigates to /sign-in by default
Log in
// Signs out all sessions; pass sessionId to target one
Log out
// Role and permission gate
Admins only}>
```
## Exported API
| Export | Kind | Purpose |
| --- | --- | --- |
| `VonvonProvider` | component | Creates VonvonClient, calls load() on mount, tears down via onCleanup |
| `createAuth` | primitive | isLoaded, isSignedIn, userId, sessionId, session, getToken, signOut as Accessors |
| `createUser` | primitive | Accessor wrapping discriminated union on isLoaded / isSignedIn / user |
| `createOrganization` | primitive | Accessor returning organization, membership, and setActive for the active org |
| `createSession` | primitive | Accessor returning session and getToken for the active session |
| `SignInButton` | component | Headless button navigating to the sign-in URL on click |
| `SignOutButton` | component | Headless button that calls signOut on click |
| `Protect` | component | Role and permission gate with fallback prop |
## Token storage
- The Vonvon Worker keeps an opaque refresh credential in an `HttpOnly` cookie. It is not a JWT, and the SDK never reads it from JavaScript or stores it in `localStorage`.
- `getToken()` returns a short-lived JWT (60 s) cached only in memory by `TokenManager` in `@vonvon-kit/core`.
# @vonvon-kit/angular
> Angular 17+ standalone provider, RxJS service, functional route guards, and standalone components on top of @vonvon-kit/core.
Locale: en
Canonical: https://vonvon.id/sdks/angular
Markdown: https://vonvon.id/sdks/angular/index.md
Source: https://vonvon.id/sdks/angular/index.mdx
## Status
Registry status: UNPUBLISHED. Install this SDK only from the repository source checkout; do not use an external package registry.
Package status is **Current package**. Angular 17+ standalone provider, RxJS service, functional guards, and standalone components are implemented. A real IdP round-trip on production infrastructure is still pending manual verification.
## Provider setup
Call `provideVonvon` in `app.config.ts`. It registers the `VONVON_CLIENT` injection token and wires an `APP_INITIALIZER` that calls `client.load()` on bootstrap. No NgModule required.
```ts
// app.config.ts
import { ApplicationConfig } from '@angular/core'
import { provideVonvon } from '@vonvon-kit/angular'
export const appConfig: ApplicationConfig = {
providers: [
// Core auth endpoints must be served on this application's exact origin.
provideVonvon({ mode: 'same-origin' }),
],
}
```
## VonvonAuthService
```ts
import { Component, inject } from '@angular/core'
import { AsyncPipe } from '@angular/common'
import { VonvonAuthService } from '@vonvon-kit/angular'
@Component({
selector: 'app-header',
standalone: true,
imports: [AsyncPipe],
template: `
@if (auth.isLoaded$ | async) {
@if (auth.isSignedIn$ | async) {
{{ (auth.user$ | async)?.primaryEmailAddress }}
} @else {
Sign in
}
}
`,
})
export class HeaderComponent {
readonly auth = inject(VonvonAuthService)
}
```
## Angular signals bridge
Use `toSignal()` from `@angular/core/rxjs-interop` to convert observables to signals for template reads.
```ts
import { toSignal } from '@angular/core/rxjs-interop'
import { inject } from '@angular/core'
import { VonvonAuthService } from '@vonvon-kit/angular'
@Component({ standalone: true, ... })
export class MyComponent {
readonly #auth = inject(VonvonAuthService)
readonly user = toSignal(this.#auth.user$, { initialValue: null })
}
```
## Route guards
```ts
import { Routes } from '@angular/router'
import { authGuard, hasOrganizationGuard, hasPermissionGuard } from '@vonvon-kit/angular'
export const routes: Routes = [
{
path: 'dashboard',
canActivate: [authGuard()],
loadComponent: () => import('./dashboard.component').then(m => m.DashboardComponent),
},
{
path: 'admin',
canActivate: [hasPermissionGuard('org:settings:write')],
loadComponent: () => import('./admin.component').then(m => m.AdminComponent),
},
]
```
## Standalone components
```html
Log inLog out
```
## Exported API
| Export | Kind | Purpose |
| --- | --- | --- |
| `provideVonvon` | function | Registers VONVON\_CLIENT singleton and APP\_INITIALIZER; accepts ProvideVonvonOptions |
| `VONVON_CLIENT` | InjectionToken | The raw VonvonClient instance; prefer VonvonAuthService for most use cases |
| `VonvonAuthService` | service | RxJS observables: state$, isLoaded$, isSignedIn$, user$, session$, organization$; plus getToken, signOut, setActiveOrganization, setActiveSession |
| `authGuard` | CanActivateFn factory | Redirects to /sign-in when user is not signed in |
| `hasOrganizationGuard` | CanActivateFn factory | Redirects when no active organization context is present |
| `hasPermissionGuard` | CanActivateFn factory | Redirects when user lacks the specified permission |
| `SignInButton` | standalone component | Selector vonvon-sign-in-button; inputs signInUrl, redirectUrl, ariaLabel |
| `SignOutButton` | standalone component | Selector vonvon-sign-out-button; inputs sessionId, redirectUrl, ariaLabel; shows aria-busy while signing out |
# @vonvon-kit/astro
> Astro integration with SSR middleware, server helpers, and island client singleton for static and server-rendered Astro sites.
Locale: en
Canonical: https://vonvon.id/sdks/astro
Markdown: https://vonvon.id/sdks/astro/index.md
Source: https://vonvon.id/sdks/astro/index.mdx
## Status
Registry status: UNPUBLISHED. Install this SDK only from the repository source checkout; do not use an external package registry.
Package status is **Current package**. The Astro integration, SSR middleware, server helpers, and island client singleton are implemented. A real IdP round-trip on production infrastructure is still pending manual verification.
## Integration setup
Register `vonvonIntegration` in `astro.config.mjs`. The integration injects server middleware with `addMiddleware` at order `pre`, keeps verification material server-side, and exposes only the serializable browser mode configuration required by client islands.
```js
// astro.config.mjs
import { defineConfig } from 'astro/config'
import { vonvonIntegration } from '@vonvon-kit/astro'
import node from '@astrojs/node'
const jwtKeyJson = process.env.VONVON_JWKS_PUBLIC_KEY
if (!jwtKeyJson) throw new Error('Missing VONVON_JWKS_PUBLIC_KEY')
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
integrations: [
vonvonIntegration({
// This combined SSR setup requires Core routes on the application's exact origin.
browser: { mode: 'same-origin' },
jwtKey: JSON.parse(jwtKeyJson),
issuer: 'https://app.example.com',
sessionTokenExchange: { endpoint: '/v1/sessions/token' },
protectedRoutes: ['/dashboard', '/account'],
signInUrl: '/sign-in',
}),
],
})
```
## Manual middleware (alternative)
```ts
// src/middleware.ts
import { sequence } from 'astro:middleware'
import { createVonvonMiddleware } from '@vonvon-kit/astro'
export const onRequest = sequence(
createVonvonMiddleware({
jwtKey: JSON.parse(import.meta.env.VONVON_JWKS_PUBLIC_KEY),
issuer: 'https://vonvon.id',
sessionTokenExchange: { endpoint: '/v1/sessions/token' },
protectedRoutes: ['/dashboard', '/account'],
signInUrl: '/sign-in',
}),
)
```
## Server-side auth in .astro pages
```astro
---
// src/pages/dashboard.astro
import { getAuth, currentUser } from '@vonvon-kit/astro/server'
const auth = getAuth(Astro.locals)
if (!auth.userId) return Astro.redirect('/sign-in')
const user = await currentUser(Astro.locals, {
secretKey: import.meta.env.VONVON_SECRET_KEY,
})
---
Welcome, {user?.primaryEmailAddress}
```
## Client island
```tsx
// src/components/SignOutButton.tsx
import { getClient } from '@vonvon-kit/astro/client'
export default function SignOutButton() {
const client = getClient()
const handleSignOut = async () => {
const result = await client.signOut()
if (!result.ok) throw new Error(result.error.message)
window.location.href = '/'
}
return
}
```
## Astro.locals typing
Add the type reference to `src/env.d.ts` to get full type coverage on `Astro.locals.vonvonAuth`.
```ts
import '@vonvon-kit/astro/locals'
```
## Exported API
| Export | Kind | Module |
| --- | --- | --- |
| `vonvonIntegration` | Astro integration factory | `@vonvon-kit/astro` |
| `createVonvonMiddleware` | middleware factory | `@vonvon-kit/astro` |
| `getAuth, currentUser, vonvonClient` | server helpers | `@vonvon-kit/astro/server` |
| `getClient, initClient, resetClient` | island client singleton | `@vonvon-kit/astro/client` |
## Security notes
- `jwtKey` is a JWKS public key; it is safe for networkless verification and does not contain a private key.
- `secretKey` (`sk_live_xxx`) must stay server-side only; never pass it to an island or client bundle.
- Protected routes redirect via `Response.redirect` in middleware before any page handler runs; no client-side JS is required.
- Forward Core opaque cookies only to an exact same-origin session-token endpoint; the value is never verified locally
# @vonvon-kit/remix
> Remix loader and action server helpers, cookie session storage, and OAuth callback handler with React SDK re-exports.
Locale: en
Canonical: https://vonvon.id/sdks/remix
Markdown: https://vonvon.id/sdks/remix/index.md
Source: https://vonvon.id/sdks/remix/index.mdx
## Status
Registry status: UNPUBLISHED. Install this SDK only from the repository source checkout; do not use an external package registry.
Package status is **Current package**. Remix loader/action auth helpers, cookie session integration, and OAuth callback handler are implemented. A real IdP round-trip on production infrastructure is still pending manual verification.
## Session storage setup
```ts
// app/sessions.server.ts
import { createVonvonSessionStorage } from '@vonvon-kit/remix'
export const sessionStorage = createVonvonSessionStorage({
secret: process.env.SESSION_SECRET!, // required: cookie signing secret
// cookieName: '__vonvon_session', maxAge: 2592000, secure: true
})
```
## Reading auth in loaders
`getAuth` verifies a Bearer token, explicit application JWT cookie, optional same-origin Core exchange, or the configured Remix session JWT, then returns an `AuthResult`. `requireAuth` throws a 302 redirect to `redirectPath` when unauthenticated.
```ts
import { getAuth, requireAuth } from '@vonvon-kit/remix'
import { json, redirect } from '@remix-run/node'
import type { LoaderFunctionArgs } from '@remix-run/node'
import { sessionStorage } from '~/sessions.server'
const jwtKey = JSON.parse(process.env.VONVON_JWKS_PUBLIC_KEY!)
const authOptions = {
jwtKey,
sessionStorage,
sessionTokenExchange: { endpoint: '/v1/sessions/token' },
}
// Optional check
export async function loader({ request }: LoaderFunctionArgs) {
const auth = await getAuth(request, authOptions)
if (!auth.userId) return redirect('/login')
return json({ userId: auth.userId, orgId: auth.orgId })
}
// Guard: throws redirect automatically when unauthenticated
export async function protectedLoader({ request }: LoaderFunctionArgs) {
const auth = await requireAuth(request, authOptions, { redirectPath: '/login' })
return json({ userId: auth.userId })
}
```
## OAuth callback handler
`handleCallback` validates the `state` parameter to prevent CSRF, exchanges the authorization code, and returns a `Response` with `Set-Cookie`.
```ts
// app/routes/auth.callback.ts
import { handleCallback } from '@vonvon-kit/remix'
import type { ActionFunctionArgs } from '@remix-run/node'
import { sessionStorage } from '~/sessions.server'
export async function action({ request }: ActionFunctionArgs) {
const result = await handleCallback(request, {
clientId: process.env.VONVON_CLIENT_ID!,
redirectUri: process.env.VONVON_REDIRECT_URI!,
sessionStorage,
defaultReturnTo: '/dashboard',
})
if (!result.ok) throw new Response(result.error, { status: 400 })
return result.response // 302 redirect + Set-Cookie
}
```
## Client provider (root.tsx)
```tsx
import { VonvonProvider } from '@vonvon-kit/remix' // re-export from @vonvon-kit/react
import { Outlet } from '@remix-run/react'
export default function App() {
return (
)
}
```
## Management API client
```ts
import { vonvonClient } from '@vonvon-kit/remix'
const client = vonvonClient({ secretKey: process.env.VONVON_SECRET_KEY! })
export async function loader() {
const result = await client.getUser('user_abc')
if (!result.ok) throw new Response(result.error.message, { status: result.error.status })
return json(result.value)
}
```
## Exported API
| Export | Kind | Purpose |
| --- | --- | --- |
| `createVonvonSessionStorage` | function | Remix cookie session storage for Vonvon tokens |
| `getAuth` | function | Verify JWT or session token; returns AuthResult |
| `requireAuth` | function | Like getAuth but throws a redirect response when unauthenticated |
| `handleCallback` | function | OAuth callback: validates state, exchanges code, sets session cookie |
| `vonvonClient` | function | Returns a server-side Management API client bound to the secret key |
| `getTokenFromSession, setTokensInSession, clearTokensFromSession` | functions | Low-level token helpers for custom session handling |
## Re-exports
Re-exports all [@vonvon-kit/react](/sdks/react) client components and hooks. `root.tsx` needs only one import for both provider and client components.
## PKCE and security
- Public clients use Authorization Code with PKCE S256. No client secret is stored.
- `handleCallback` validates the `state` parameter against the session to prevent CSRF.
- Access tokens are stored in `HttpOnly` session cookies; they are never written to `localStorage`.
# @vonvon-kit/expo
> Expo SecureStore and WebBrowser adapters for @vonvon-kit/react-native plus an Expo Router route guard hook.
Locale: en
Canonical: https://vonvon.id/sdks/expo
Markdown: https://vonvon.id/sdks/expo/index.md
Source: https://vonvon.id/sdks/expo/index.mdx
## Status
Registry status: UNPUBLISHED. Install this SDK only from the repository source checkout; do not use an external package registry.
Package status is **Current package**. Expo SecureStore and WebBrowser adapters, VonvonProvider, and Expo Router route guard hook are implemented. A real IdP round-trip on production infrastructure is still pending manual verification.
All PKCE logic, token exchange, and session management live in [@vonvon-kit/react-native](/sdks/react-native); this package provides adapters and Expo Router integration only.
## Provider setup
Inject `createSecureStoreAdapter` and `createExpoWebBrowserAdapter` into `VonvonProvider`. No top-level Expo module import is needed; adapters accept module instances so CI typecheck stays clean without Expo peer deps installed.
```tsx
import * as SecureStore from 'expo-secure-store'
import * as WebBrowser from 'expo-web-browser'
import { VonvonProvider, createSecureStoreAdapter, createExpoWebBrowserAdapter } from '@vonvon-kit/expo'
const tokenCache = createSecureStoreAdapter({ secureStore: SecureStore })
const browser = createExpoWebBrowserAdapter({ webBrowser: WebBrowser })
export default function App() {
return (
)
}
```
## Sign in and sign out
```tsx
import { useSignIn, useSignOut } from '@vonvon-kit/expo'
import { Button } from 'react-native'
function SignInScreen() {
const { signIn, signInState } = useSignIn()
return (