Skip to content
dhanu docs
Browse pages

OAuth apps

OAuth 2.1 apps

Let people connect your app to their own Dhanu workspace, authorization code with PKCE, a consent screen, per-user tokens, refresh and revocation.

An API key acts for the workspace that minted it. An OAuth app acts for a person who signed in and said yes: they see what your app asks for, pick one of their workspaces, and your app receives tokens scoped to exactly that. Dhanu is an OAuth 2.1 authorization server: authorization code with PKCE only, no implicit or password grants, exact redirect-URI matching, refresh-token rotation.

1. Register the app

In the developer console (Developers → OAuth apps) register an app under a project. You choose its redirect URIs (https, http://localhost for development, or a custom scheme for native apps), the scopes it may ever ask for, and whether it is a server-side app (gets a client secret, shown once) or a native / single-page app (no secret, PKCE alone protects the exchange).

The app starts unverified. Unverified apps can ask for the everyday scopes; sensitive ones, writing files, reading files, searching the brain, running workflows, rendering video, need verification.

2. Send the person to authorize

https://app.dhanu.ai/oauth/authorize
  ?response_type=code
  &client_id=dhanu_oc_…
  &redirect_uri=https://app.example.com/oauth/callback
  &scope=openid%20offline_access%20tasks.create%20tasks.read
  &state=…
  &code_challenge=…
  &code_challenge_method=S256

They sign in (social, passkey, MFA, the same sign-in as the app), see your app’s name and each scope in plain words, choose a workspace, and approve. Dhanu redirects back to redirect_uri with code and your state. A refusal returns error=access_denied. Scopes are the same ids the API catalogue uses, plus openid, profile, email and offline_access (which is what earns a refresh token).

3. Exchange the code

curl -X POST https://api.dhanu.ai/api/v1/oauth/token \
  -u "dhanu_oc_…:dhanu_ocs_…" \
  -d grant_type=authorization_code \
  -d code=dhanu_ac_… \
  -d redirect_uri=https://app.example.com/oauth/callback \
  -d code_verifier=…
const response = await fetch("https://api.dhanu.ai/api/v1/oauth/token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    grant_type: "authorization_code",
    client_id: process.env.DHANU_CLIENT_ID,
    client_secret: process.env.DHANU_CLIENT_SECRET,
    code,
    redirect_uri: "https://app.example.com/oauth/callback",
    code_verifier: verifier,
  }),
});
const { access_token, refresh_token, expires_in } = await response.json();
import requests

tokens = requests.post(
    "https://api.dhanu.ai/api/v1/oauth/token",
    auth=(CLIENT_ID, CLIENT_SECRET),
    data={
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": "https://app.example.com/oauth/callback",
        "code_verifier": verifier,
    },
).json()

The response is the standard shape: access_token (dhanu_at_…, valid for one hour), token_type: Bearer, expires_in, scope, and refresh_token (dhanu_rt_…, valid for 30 days) when offline_access was granted. Client credentials go in an HTTP Basic header or in the body; a public client sends only client_id. Codes are single use and expire after ten minutes.

4. Call the API as the user

An access token is a bearer token on the public API, exactly like an API key:

curl https://api.dhanu.ai/api/pub/v1/me -H "Authorization: Bearer dhanu_at_…"

Every SDK accepts it in place of a key, new Dhanu(accessToken). The token carries the workspace the person chose and only the scopes they approved; a call outside them answers 403 with api_key_operation_scope. Credits are spent from their workspace, and usage is attributed to your app’s project in the request log.

5. Refresh and revoke

curl -X POST https://api.dhanu.ai/api/v1/oauth/token \
  -u "dhanu_oc_…:dhanu_ocs_…" -d grant_type=refresh_token -d refresh_token=dhanu_rt_…

curl -X POST https://api.dhanu.ai/api/v1/oauth/revoke \
  -u "dhanu_oc_…:dhanu_ocs_…" -d token=dhanu_at_…

Refreshing rotates: the old access and refresh tokens stop working the moment the new pair is issued. revoke takes either token. People can also cut an app off themselves from Settings → Connected apps, which revokes every token and the consent; the next authorize shows the consent screen again.

Discovery

GET https://api.dhanu.ai/api/v1/oauth/.well-known/oauth-authorization-server returns RFC 8414 metadata, endpoints, supported grants and scopes, for clients that configure themselves.