Connect your first application
By the end of this guide, a user will sign in on your Udibo tenant, return to your application, and call an API protected by their application session. Start with one development application and one test account.
Before you start
You need private-beta access, a tenant you can manage, and a web application with a backend. Start at Udibo for access. If you are waiting, run the local package quickstart to explore the flow.
In the dashboard, Identity lists the tenants you can manage. Create or select a development tenant, then keep its dashboard open while connecting your app. If you cannot access a required setting, ask your tenant administrator to grant the corresponding access; an application user's role does not grant dashboard administration.
For a new project, choose a starter. For an existing app, add this integration alongside your current login and switch it on for test accounts first. Follow the migration plan before moving users.
1. Register the application
Open your tenant's Applications page and choose Create application. For a web app whose backend handles the callback:
| Setting | Development starting point | Why |
|---|---|---|
| Name | A name you recognize, such as “My app development” | Distinguishes this registration from production |
| Environment | Development | Permits a local HTTP callback |
| Confidential client | Enabled | Your backend can protect the client secret |
| Grants | Authorization Code and Refresh Token | Signs users in and renews their access |
| Redirect URIs | Your app's complete callback URL | The service returns the browser here after sign-in |
| Access token format | Opaque | Your API validates tokens by introspection |
For example, an app running at http://localhost:8000 with its BFF mounted at
/auth uses http://localhost:8000/auth/callback. Match the actual port and
path. Use that same URL in your application's configuration.
Save the application. Saving creates the client ID; it does not create a secret. On the application's detail page, use Create new secret and store the one-time value in your backend's secret configuration. Secret management requires separate administrator permission.
The application configuration guide explains token formats, scopes, production callbacks, and public clients.
2. Gather the configuration
Keep these values together for this environment:
The tenant's trusted issuer URL, supplied through your beta setup
This application's client ID and client secret
The exact callback URL you just registered
The scopes your integration needs; request
openid, and addprofileandemailwhen you need those identity claimsA separate, high-entropy application secret to protect pending login state
The issuer is the identity host, not your application's host and not the
dashboard URL. Read its discovery document at
{issuer}/.well-known/oauth-authorization-server; the client can discover the
protocol endpoints instead of copying them into every route.
Use environment variables or your deployment's secret manager for credentials. Do not put the client secret in browser configuration, a public repository, or an agent prompt.
3. Connect the backend and browser
Follow Use Udibo's identity service. It contains the checked Hono BFF wiring and the browser client in one place.
The integration has three pieces:
Your backend mounts
HonoBffat/auth, exchanges the authorization code, and stores the application's session.Your API validates the access token. With opaque tokens, use introspection against the issuer, as shown in Protect an API.
Your browser uses
BffClientto start login and make authenticated requests to the same application origin. React applications can use the package's provider and hooks for session presentation.
The guide explicitly marks the session store and resource server as dependencies you supply. A declared variable in a snippet is not a working database adapter. Use a runnable example if you want to inspect all the pieces together before adapting an existing application.
4. Complete a sign-in
Use a test user in the tenant. For self-registration, configure the tenant's sign-up mode to allow it and enable the intended sign-in method. A closed sign-up mode does not prevent an existing eligible user from signing in.
Open your application in a browser and start login from the application. The browser should visit the tenant's hosted sign-in page, complete authentication, and return to your registered callback. Your app then reports an authenticated session.
Checkpoint: a protected request succeeds while signed in. In a separate signed-out browser context, the same protected request is refused. Signing out ends the application's session; the tenant's SSO session is a separate session, so test the logout behavior you intend to offer.
Account sessions in your application
Use the person's access token on your tenant's host to build device controls:
| Request | Result |
|---|---|
GET /api/account/sessions | {sessions: [...]} with opaque IDs, creation and activity times, address, user agent and a current marker |
DELETE /api/account/sessions/{sessionId} | 204 after revoking one other login session |
POST /api/account/sessions/revoke-others | {revoked: number} after revoking the person's other login sessions |
These operations require no additional scope or dashboard seat. The credential selects the person and tenant; request parameters cannot select another account. Machine credentials are refused. Session lists exclude revoked, expired and idle sessions and never include secrets or tokens.
current identifies the login that issued the credential. A credential can
outlive that login: then no row is current, and revoke-others returns 409 with
reason: "current_session_required". Deleting the current login returns 409
with reason: "current_session"; use the tenant's end-session endpoint to sign
out. An unknown session ID and another person's ID both return the same 404.
Revocation stops session-owned tokens on the next request. A third-party grant
that originated from the login retains its existing lifetime. Revoke-others also
revokes idle sessions, even though the list omits them. Mutations accept no body
or an empty object and share a budget of 30 attempts per minute per person with
the hosted security page. A 429 includes Retry-After in seconds.
5. Make the first success repeatable
Repeat the flow after reloading the page and after restarting the backend
Confirm expired or revoked sessions cannot be restored by a refresh race
Confirm the browser has no access or refresh tokens in local storage
Test one operation without its required permission; it must be refused
Use troubleshooting if a checkpoint fails. Once it passes, choose sign-in methods, add organizations and permissions where needed, and work through the production checklist.
Last verified 2026-09-09.

