Buko Docs

Sign in with Buko

Identity-only sign-in for websites and native applications. The protocol returns a short-lived, signed ID token. It does not issue access tokens, refresh tokens, client secrets for public apps, or permissions to read messages and contacts. It is not a full OAuth/OIDC provider; use this guide and the supplied adapters instead of assuming compatibility with an arbitrary OIDC discovery client.

Availability

Deployment, signing keys and the service feature gate must be enabled before integrations can run. Creating a draft does not grant public access. Only its owner can test a draft; public sign-in requires administrative approval.

Accounts, clients and keys belong to the selected product. Never exchange a Buko code with another product's service.

Register an application

Provide an application name (60 characters), description (500), HTTPS icon URL, HTTPS website URL, HTTPS privacy-policy URL and contact email. Contact email is visible to reviewers, not to users or other applications.

An account can create 5 applications. Each application supports one client for each of Web, iOS, Android and macOS. Platform clients have different client_id values but share the application's stable account identity. Different applications receive different account identifiers.

PlatformRequired configuration
WebUp to 5 exact HTTPS Origins; optional exact full-page redirect URLs
iOS / macOSBundle ID, Apple Team ID; generated callback Scheme and optional registered callbacks
AndroidPackage name, signing-certificate SHA-256 fingerprint; generated callback Scheme and optional registered callbacks

Each client supports up to 5 exact callback URLs. No wildcards, userinfo, fixed query parameters or fragments. Web redirects must belong to registered Origins. An Origin contains scheme, host and optional port, for example https://example.com; it does not contain a path. Localhost and IP hosts are not accepted. Use a controlled HTTPS development domain for testing.

For each configured Web / HTTPS callback host, add the TXT record displayed in the console, then click Verify DNS. Example:

Name: _buko-signin.example.com
Type: TXT
Value: copy the complete generated value from the console

Proofs are valid for 30 days when testing drafts or submitting for review. An approved snapshot remains published until replaced or suspended; proof expiry alone does not silently disable a reviewed production integration.

Saving changes updates the draft only. Submit the draft for review to publish changes to an approved application. Pending/rejected edits do not change the currently approved configuration. Sensitive edits and submission require a real sign-in within 10 minutes; ordinary SSO and QR login do not reset that timer.

Web: popup sign-in

Register your website Origin. No callback backend or redirect URL is needed for popup mode. Copy the SDK into your own build (recommended), or serve it from the published SDK URL with the appropriate CORS policy. The source package is packages/identity-signin-web; it has no runtime dependencies.

import { createSignIn } from './sign-in-v1.mjs';

const identity = createSignIn({
  product: 'buko',
  clientId: 'COPY_WEB_CLIENT_ID',
});

// Call directly in a click handler; do not await anything before opening it.
document.querySelector('#sign-in').addEventListener('click', async () => {
  try {
    const { id_token, claims } = await identity.signInWithPopup();
    // Signature, issuer, audience, nonce and expiry have already been checked.
    showSignedInUser({ issuer: claims.iss, subject: claims.sub });
  } catch (error) {
    if (error.code !== 'cancelled' && error.code !== 'access_denied') {
      showSignInError(error.code);
    }
  }
});

The SDK retains PKCE/state/nonce in memory and checks message Origin, source window and state. The authorization window returns only code / error and state in a type: "identity.signin.result" message to the exact registered Origin. A blocked popup reports popup_blocked; do not automatically open a second authorization channel after a user refuses or cancels.

Do not apply a COOP policy that severs the popup's opener while expecting popup messages. Test deployed headers, Safari and popup blockers. If your site needs strong opener isolation, offer full-page redirect mode instead.

Web: optional full-page redirect

Register the complete callback URL, then:

// Initiating page:
await identity.startRedirect({ redirectUri: 'https://example.com/sign-in/return' });

// Callback page, before rendering any third-party analytics or remote content:
const { id_token, claims } = await identity.completeRedirect();

The SDK stores only short-lived transaction data in same-tab sessionStorage, consumes it once, removes code/state from the address bar, exchanges the code and verifies the ID token. It does not store an official messenger session or share cookies across domains. Callback pages should use Referrer-Policy: no-referrer.

Native applications

The Flutter adapter is in packages/identity-signin-flutter. It supports iOS and Android official-App authorization, with system-browser fallback after a confirmed launch failure. macOS uses the system authentication browser. The adapter's Apple browser path currently uses the generated custom Scheme; platform-native integrations can also use registered verified HTTPS callbacks.

final signIn = NiximSignIn(
  product: IdentityProduct.buko,
  clientId: 'COPY_PLATFORM_CLIENT_ID',
  callbackUri: Uri.parse('COPY_GENERATED_CALLBACK_URL'),
);
final result = await signIn.signIn();
// result.claims has been verified; result.subject is app-specific.
// Explicit browser retry, if the user chooses it:
// await signIn.signIn(preferOfficialApp: false);

Register the generated Scheme in the receiving app. For iOS use CFBundleURLTypes / CFBundleURLSchemes in Info.plist. For Android register a VIEW + DEFAULT + BROWSABLE intent filter on your singleTop activity, restricted to your exact scheme and callback path; enable app_links handling and disable Flutter's competing automatic deep-link handler. For macOS register the Scheme in Info.plist and enable outgoing network access. No Apple Developer / Google Cloud entry is required merely to declare a custom Scheme. Verified HTTPS links need the platform's domain association files and entitlements instead.

The SDK directly launches the fixed official Android package or an iOS Universal Link with universalLinksOnly. It performs no installed-package query and adds no <queries>, QUERY_ALL_PACKAGES or LSApplicationQueriesSchemes declarations. Android browser fallback uses Custom Tabs; Apple uses ASWebAuthenticationSession. Use a cancel button wired to signIn.cancel() while waiting. Android browser closure does not reliably report cancellation; explicit cancellation or the bounded timeout ends that attempt. Process death discards the in-memory verifier; start again rather than accepting an unbound callback.

Custom Schemes are not exclusive ownership proofs. PKCE prevents a different app that intercepts the code from redeeming it without the verifier. Platform metadata and the public client ID are not App Attest / Play Integrity evidence.

Native protocol

All secrets below are independent random 32-byte values, encoded as unpadded base64url (43 characters). Generate them with a cryptographically secure source. code_challenge is base64url(SHA-256(verifier)); only S256 is supported.

POST https://auth.buko.app/identity/native/requests
Content-Type: application/json

{
  "client_id": "COPY_PLATFORM_CLIENT_ID",
  "response_type": "code",
  "scope": "openid",
  "response_mode": "query",
  "destination": "COPY_REGISTERED_CALLBACK_URL",
  "state": "RANDOM_43_CHARACTER_VALUE",
  "nonce": "ANOTHER_RANDOM_43_CHARACTER_VALUE",
  "code_challenge": "SHA256_VERIFIER_BASE64URL",
  "code_challenge_method": "S256"
}

Response: {id, launch_ticket, requester_secret, expires_at}. Launch:

https://auth.buko.app/identity/open-app#request_id=ID&launch_ticket=TICKET

Keep requester_secret and verifier inside the requesting app. Never put them in links, analytics, logs or QR codes. The native launch ticket is valid for 120 seconds. Only the signed-in official phone can read the application details and approve or refuse this request. After approval the code gets a full 60-second redemption window. Status polling never returns the code or user identity.

POST /identity/native/requests/{id}/status and /cancel accept JSON {requester_secret}. Do not poll faster than 2 seconds. These endpoints do not accept a browser Origin. A browser authorization must be created through the authorization center, not by obtaining native approval secrets in JavaScript.

If the official App cannot be launched, cancel the native request first and create a new browser authorization with fresh state, nonce and verifier. Never fall back after refusal, cancellation or timeout. The native fallback landing page does not approve the native ticket in a browser.

Browser authorization parameters

Open https://auth.buko.app/identity/authorize with these query parameters:

ParameterValue
client_idRegistered platform client ID
response_typecode
scopeopenid or omitted
response_modeweb_message for Web popup; query for registered redirect
destinationExact registered Origin (popup) or full callback (redirect)
stateRandom per-attempt 43-character base64url value
nonceIndependent random per-attempt 43-character base64url value
code_challengeS256 challenge
code_challenge_methodS256

Browser requests last 10 minutes. Approval codes last at most 60 seconds, bounded by the request deadline. The user confirms every third-party authorization even when already signed in. Login/signup share the same entry; the service determines whether the account already exists. QR authentication first signs into the official center; it does not skip third-party confirmation.

Exchange the code

POST https://auth.buko.app/identity/token?client_id=COPY_PLATFORM_CLIENT_ID
Content-Type: application/json

{
  "grant_type": "authorization_code",
  "client_id": "COPY_PLATFORM_CLIENT_ID",
  "response_mode": "query",
  "destination": "COPY_REGISTERED_CALLBACK_URL",
  "code": "RECEIVED_CODE",
  "code_verifier": "ORIGINAL_VERIFIER"
}

Popup exchanges use response_mode: "web_message" and the original Origin as destination. The body and query client IDs must agree. Browser requests use JSON and exact-Origin CORS preflight; omit credentials. Native HTTP exchanges do not send a browser Origin. The code is atomically consumed once; concurrent redemption has one winner. If an exchange result is lost, start a new sign-in.

{ "id_token": "SIGNED_RS256_JWT", "id_token_expires_in": 300 }

Do not expect access_token, refresh_token or token_type.

Verify identity

Use the fixed product issuer's /identity/jwks.json; never follow a token's jku, x5u or arbitrary key URL. Accept only RS256 and the expected kid from these public keys. Verify the actual signature and all of:

Store (iss, sub) as the account key. Do not use a nickname, handle, email or phone number as the unique identity. The same application gets the same subject across its platform clients; different applications get different subjects. There is no userinfo endpoint in this version.

An application may have no backend or existing account system: it can use the verified identity directly for local personalization. If it has protected server data, its server must verify the ID token and bind the nonce to its own login attempt before creating its own session; client-side verification does not protect a server from forged requests.

Errors and revocation

access_denied / cancelled mean the user stopped the attempt. invalid_grant means the code/request is expired, consumed, changed or no longer authorized. rate_limited requires backoff. identity_unavailable means the service gate or signing configuration is unavailable. Do not silently retry one-use exchanges.

Users can revoke an application's grant in Settings → Privacy and security → Authorized applications. Revocation invalidates unconsumed codes and requires a new approval. It cannot instantly erase already-issued offline-verifiable ID tokens or terminate a third party's own sessions. Apps and administrators can disable an integration; new approvals and exchanges then fail.

Implementation checklist

  1. Create the application and configure the correct platform client.
  2. Verify domains; test only with the owning account until approved.
  3. Register the exact callback or Origin and keep verifier/state/nonce per attempt.
  4. Validate full callback, state and JWT; do not trust decoded JSON alone.
  5. Test refusal, app absence, popup blockers, duplicate callbacks, expiry, account switching, revoked grants and network loss.
  6. Submit for review. Changes to published configuration require a new review.