Sign in with Bynli
OAuth 2.0 / OpenID Connect
Add a "Sign in with Bynli" button to your site or app. Bynli is a standards-compliant OAuth 2.0 / OpenID Connect provider — the same flow you use for Google, Apple, or Microsoft.
Issuer
All flows start at id.bynli.com — the dedicated auth
domain. Bookmark the discovery document if your client supports
auto-configuration:
GET https://id.bynli.com/.well-known/openid-configuration
It advertises the canonical endpoints:
| Endpoint | URL |
|---|---|
| Authorization | https://id.bynli.com/oauth/authorize |
| Token | https://id.bynli.com/oauth/token |
| UserInfo | https://id.bynli.com/oauth/userinfo |
| JWKS | https://id.bynli.com/oauth/jwks.json |
Tokens are signed RS256. Always validate iss equals
https://id.bynli.com and aud equals your
client_id before trusting the claims.
Register a client
Team admins register OAuth clients at
/dash/sites/oauth. Each client is
scoped to one team and gets a unique client_id.
Site-registered clients are public clients:
- No
client_secret— they run in browsers and can't keep one. - PKCE is required on every authorization request.
- Scopes are limited to
openid profile email(more on request). - Redirect URIs are exact-matched and must be HTTPS (or
http://localhostfor development).
The flow (PKCE)
- Generate a high-entropy
code_verifier(43–128 chars). Computecode_challenge = BASE64URL(SHA256(code_verifier)). - Redirect the user to:
Step 1 — AuthorizeGET
https://id.bynli.com/oauth/authorize ?client_id=site_xxxxxxxxxxxx &redirect_uri=https://yoursite.com/auth/callback &response_type=code &scope=openid+profile+email &state=<random> &code_challenge=<S256-of-verifier> &code_challenge_method=S256
- The user signs in (if needed) and approves the scopes. Bynli redirects back to your
redirect_uriwith?code=…&state=…. Verifystatematches what you sent. - Exchange the code for tokens:
Response (JSON):Step 2 — Token exchangePOST
POST https://id.bynli.com/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code=<code> &redirect_uri=<same redirect_uri> &client_id=site_xxxxxxxxxxxx &code_verifier=<the verifier>
access_token,refresh_token,id_token(JWT),expires_in,token_type=Bearer,scope. - Verify the
id_token: signature against/oauth/jwks.json,iss == https://id.bynli.com,aud == your client_id, expiry. - Call
GET /oauth/userinfowithAuthorization: Bearer <access_token>for profile claims (or just trust the id_token claims for openid + profile + email).
Silent sign-in
For returning users already signed into Bynli, pass prompt=none on the authorize call. The server either redirects back with a code immediately (no UI shown) or returns one of these errors so your client can fall back to manual sign-in:
| Error | Meaning |
|---|---|
login_required | User has no active Bynli session — show the manual button. |
consent_required | User is signed in but hasn't yet approved your scopes — start the normal flow. |
Scopes
| Scope | Grants |
|---|---|
openid | Required. Identifies this as an OIDC request and authorizes an id_token. |
profile | Name, username, profile picture. |
email | Email address + verification status. |
phone | Phone number + verification status. Available to first-party clients only at this time. |
Additional scopes (teams:read, wallet:read, tasks:read, purchases:read, feeds:read) exist for first-party Bynli apps and aren't open to site-registered clients yet. Reach out if your use case needs one.
Subject identifier (sub)
The sub claim is a stable, opaque, per-issuer user identifier. Treat it as your primary key when storing per-user data on your side — never key on email (which can change) or display name. Two different Bynli users will never share a sub; the same user signing into two different clients gets the same sub.
Errors
Returned as standard OAuth error params on the redirect_uri or as JSON from the token endpoint:
| Error code | When |
|---|---|
invalid_request | Missing required parameter, bad redirect_uri, or missing PKCE. |
invalid_client | client_id is unknown, inactive, or doesn't match the redirect_uri. |
invalid_grant | code expired (10-minute TTL), already used, or code_verifier doesn't match the original challenge. |
invalid_scope | Requested a scope not allowed for this client. |
access_denied | User clicked Deny on the consent screen. |
login_required / consent_required | Silent (prompt=none) flow couldn't complete without UI. |
Revocation
Users can revoke your client's access at /dash/me/apps. When revoked, the consent record is deleted and every outstanding access + refresh token is marked revoked. Your next call to /oauth/token with a refresh token will return invalid_grant; access tokens stop working immediately.
The browser kit (for static sites)
If your site is hosted by Bynli (*.site.bynefit.com or a verified custom domain), the auth module of the Bynli kit wraps the entire flow into one config block plus a couple of HTML attributes — no PKCE plumbing required. See the site-config guide.
CORS
/oauth/token, /oauth/userinfo, and
/oauth/jwks.json respond with
Access-Control-Allow-Origin: * so browser-based clients
on any origin can call them. Credentials are never echoed — the
flow's security comes from PKCE plus the redirect-URI allowlist on
your client.