Documentation
Quickstart
Connect a signed-in user and give their connected tools to an AI runtime.
This server-first path lists your tenant catalog, creates an origin-bound connect session, and loads one authenticated user's executable tools. Provider calls leave from your SaaS runtime; Authlane remains the control plane.
1. Initialize Authlane on your server
pnpm add @authlane/sdkimport { Authlane } from '@authlane/sdk';
const authlane = new Authlane({
apiKey: process.env.AUTHLANE_API_KEY!,
});Keep AUTHLANE_API_KEY in a trusted server environment. The API-key SDK rejects browser usage.
2. List the services your tenant enabled
export async function listServices() {
const { data: services, error } = await authlane.services.list();
// Expected failures arrive as values. Nothing here throws.
if (error) return { data: null, error };
return { data: services, error: null };
}An empty array is a valid result: enable a service in the tenant dashboard before offering a connect action.
3. Create a connect session for the signed-in user
export async function createConnectSession(userId: string) {
const { data, error } = await authlane.connectSessions.create({
externalUserId: userId,
allowedServices: [], // every service enabled right now
allowedOrigin: 'https://app.example.com',
expiresInSeconds: 600,
});
if (error) return { data: null, error };
// Only the URL goes to the browser. It carries no API key.
return { data: { connectUrl: data.url }, error: null };
}allowedServices: [] takes a one-time snapshot of every service currently enabled for this
tenant. Later additions are not included. Return only data.url to the browser.
4. Render the hosted connect UI
pnpm add @authlane/reactimport { AuthlaneConnect } from '@authlane/react';
export function Integrations({ connectUrl }: { connectUrl: string }) {
return <AuthlaneConnect connectUrl={connectUrl} />;
}The short-lived URL already binds the tenant, signed-in external user, service snapshot, exact parent origin, and expiry. Neither the Authlane API key nor provider credentials enter React.
5. Give this user's tools to your AI runtime
Install the packages for the runtime you use:
pnpm add @authlane/sdk @authlane/ai ai zodpnpm add @authlane/sdk @authlane/ai @openai/agents zodpnpm add @authlane/sdk @authlane/ai @mastra/core zodpip install 'authlane[agno]'pip install 'authlane[langchain]' langchainpnpm add @authlane/sdk @authlane/ai @modelcontextprotocol/sdk zodEach panel is a complete server-side flow. Bind the authenticated external user before selecting the adapter.
import { vercelAI } from '@authlane/ai/vercel';
import type { ModelMessage } from 'ai';
import { createTextStreamResponse, streamText, toTextStream } from 'ai';
export async function answer(userId: string, messages: ModelMessage[]) {
// Tools are bound to this user, so the model only ever sees what they connected.
const { data: tools, error } = await authlane
.user(userId)
.tools.list({ adapter: vercelAI() });
if (error) return Response.json({ error }, { status: error.statusCode ?? 400 });
const result = streamText({ model: 'openai/gpt-5-mini', messages, tools });
return createTextStreamResponse({ stream: toTextStream({ stream: result.stream }) });
}import { openAIAgents } from '@authlane/ai/openai';
import { Agent, run } from '@openai/agents';
export async function answer(userId: string, prompt: string) {
const { data: tools, error } = await authlane
.user(userId)
.tools.list({ adapter: openAIAgents() });
if (error) return { data: null, error };
const agent = new Agent({
name: 'Assistant',
instructions: 'Use connected tools.',
tools,
});
const result = await run(agent, prompt);
return { data: result.finalOutput, error: null };
}import { mastraAI } from '@authlane/ai/mastra';
import { Agent } from '@mastra/core/agent';
export async function answer(userId: string, prompt: string) {
const { data: tools, error } = await authlane
.user(userId)
.tools.list({ adapter: mastraAI() });
if (error) return { data: null, error };
const agent = new Agent({
id: 'assistant',
name: 'Assistant',
instructions: 'Use connected tools.',
model: 'openai/gpt-5-mini',
tools,
});
return { data: await agent.generate(prompt), error: null };
}import os
from dataclasses import dataclass
from agno.agent import Agent
from authlane import Authlane
from authlane.adapters import agno
@dataclass(frozen=True)
class CurrentUser:
id: str
def answer(current_user: CurrentUser, prompt: str):
with Authlane(api_key=os.environ["AUTHLANE_API_KEY"]) as authlane:
user = authlane.user(current_user.id)
result = user.tools.list(adapter=agno())
if result.error is not None:
return result
assert result.data is not None
return Agent(tools=result.data).run(prompt)import os
from dataclasses import dataclass
from authlane import Authlane
from authlane.adapters import langchain
from langchain.agents import create_agent
from langchain_core.language_models import BaseChatModel
@dataclass(frozen=True)
class CurrentUser:
id: str
def answer(current_user: CurrentUser, prompt: str, model: BaseChatModel):
with Authlane(api_key=os.environ["AUTHLANE_API_KEY"]) as authlane:
user = authlane.user(current_user.id)
result = user.tools.list(adapter=langchain())
if result.error is not None:
return result
assert result.data is not None
agent = create_agent(model=model, tools=result.data)
return agent.invoke({"messages": [{"role": "user", "content": prompt}]})import { mcpServer } from '@authlane/ai/mcp';
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
export async function connectMcp(userId: string, transport: Transport) {
const { data: server, error } = await authlane
.user(userId)
.tools.list({ adapter: mcpServer() });
if (error) return { data: null, error };
await server.connect(transport);
return { data: server, error: null };
}Listing tools reads definitions and status; it does not issue credentials. A generated callback requests one fresh, audited, access-only lease only when invoked, then the local integration calls the provider directly. Move body limits, route authentication, rate limiting, and redacted logging into the production hardening guide.