Authentication
This page is code only. Choose the model first in Sign-in for your users, and create the credential with the CLI or the dashboard.
API key
Set the Introspection project API key as INTROSPECTION_TOKEN. The server-side SDK reads it automatically:
export INTROSPECTION_TOKEN="intro_..."JavaScript
import { IntrospectionClient } from "@introspection-sdk/introspection-node";
const client = new IntrospectionClient();
// Or pass it explicitly.
const explicit = new IntrospectionClient({
token: process.env.INTROSPECTION_TOKEN,
});The base API URL defaults to https://api.introspection.dev. Override it with INTROSPECTION_BASE_API_URL when targeting another deployment.
Key properties: Credentials. The same token authenticates the OTLP exporters.
Never put an API key in browser code, a mobile application, or an agent sandbox. Anything shipped to an end user must be treated as public.
Service-account application
A confidential service-account application exchanges its client ID and secret for a short-lived token through OAuth client_credentials:
JavaScript
import { IntrospectionClient } from "@introspection-sdk/introspection-node";
const client = await IntrospectionClient.fromServiceAccount({
clientId: process.env.INTROSPECTION_SERVICE_ACCOUNT_CLIENT_ID,
clientSecret: process.env.INTROSPECTION_SERVICE_ACCOUNT_CLIENT_SECRET,
project: process.env.INTROSPECTION_PROJECT,
});The token is scoped to the project and capped to the application’s allowed scopes. It lasts 60 minutes and never refreshes: mint again before it expires. IntrospectionLogs keeps one token for life, so give it an API key.
To run work for one of your users, pass identity: { user_id } when you open
the runner (ownership).
Federated application
For a federated application, your backend exchanges the end user’s signed IdP token through RFC 8693 token exchange and opens the runner with the result: If users sign in with your identity provider. A native app can run the exchange on the device: Build a native app.
Native application (email-code sign-in)
A native application signs users in to Introspection accounts with an
emailed code (for your own identity provider, use federation above). It is a
public client with no secret and calls the Control Plane’s /v1/oauth
endpoints directly:
- Send a code.
POST /v1/oauth/email/codewith a JSON body{ "client_id", "email", "project" }(projectis the slug or id). It always answers202, whether or not the email has an account. - Verify the code.
POST /v1/oauth/token, form-encoded, withgrant_type=urn:introspection:params:oauth:grant-type:email_code,client_id,email,code, andproject. A success returnsaccess_token,refresh_token,session_id,org_id,project_id,dp_url, andmember_id. - Refresh and sign out. Refresh with the
refresh_tokengrant and the sameclient_id. Sign out withPOST /v1/oauth/revoke(client_id,session_id,org_id).
Sign-up is open: any email becomes a customer member on its first successful
sign-in. Treat the code as an opaque string: a new user’s first code can
contain letters, so do not restrict the field to digits or a fixed length. A
code expires after 10 minutes, allows five attempts, and is replaced by the
next one sent to the same address.
| Response | Meaning |
|---|---|
400 invalid_request | The email is malformed, or email, code, or project is missing. |
400 invalid_client | client_id is not a native application, or project is not in its organization. |
400 invalid_grant | The code is wrong, expired, used, replaced, or out of attempts. |
409 account_exists | The email already belongs to another member of the organization. |
429 slow_down | Too many codes were requested. Wait for Retry-After. An address can receive one code per minute and five per hour. |
503 temporarily_unavailable | Sign-in could not be checked right now. Try again. |
Browser token broker
A browser never holds an API key or service-account secret. Your backend opens
an identity-bound runner (service account) or exchanges the user’s IdP token
(federated), then returns { token, runtimeId, dpUrl }. Both brokers:
Add a chat to your web app.
Hosted browser login
An spa application uses hosted login with authorization code + PKCE and no secret. After the redirect, your backend exchanges the code, redirect URI, and PKCE verifier:
import { authorizationCodeToken } from "@introspection-sdk/introspection-node";
// In your backend, after the hosted-login redirect.
const token = await authorizationCodeToken({
code, // from the redirect URI
clientId: process.env.INTROSPECTION_SPA_CLIENT_ID, // public client, no secret
redirectUri, // must match the authorize call
codeVerifier, // pairs with the PKCE challenge
});Python: authorization_code_token(...) (async: async_authorization_code_token). Rust: auth::authorization_code_token(...) with AuthorizationCodeParams.
Next
- Sign-in for your users: choose the model.
- Web chat: the browser broker end to end.