update docs

This commit is contained in:
Alex Holovach
2025-10-03 07:33:32 -05:00
parent 5fe1f749e9
commit 923813d640
2 changed files with 52 additions and 200 deletions
+44 -191
View File
@@ -1,6 +1,6 @@
# @kubiks/otel-better-auth
OpenTelemetry instrumentation for [Better Auth](https://better-auth.com/). One-line setup for complete auth observability on both server and client.
OpenTelemetry instrumentation for [Better Auth](https://better-auth.com/). One-line setup for complete auth observability across all auth flows.
## Installation
@@ -14,54 +14,28 @@ pnpm add @kubiks/otel-better-auth
## Usage
### Server-Side with Plugin (Recommended for HTTP-level tracing)
Use the plugin to trace all HTTP requests, including OAuth callbacks and social sign-ins:
### Quick Start
```typescript
import { betterAuth } from "better-auth";
import { otelPlugin } from "@kubiks/otel-better-auth";
import { instrumentBetterAuth } from "@kubiks/otel-better-auth";
export const auth = betterAuth({
database: db,
plugins: [otelPlugin()],
// ... your config
});
export const auth = instrumentBetterAuth(
betterAuth({
database: db,
// ... your Better Auth config
}),
);
```
**This is the recommended approach** as it captures:
- ✅ OAuth callbacks with user ID
- ✅ Social sign-ins with user ID
- ✅ All HTTP-based auth operations
- ✅ Email verification, password reset, etc.
### Server-Side with Wrapper (For direct API calls)
If you call `auth.api.*` methods directly in your code, also wrap the instance:
```typescript
import { betterAuth } from "better-auth";
import { instrumentBetterAuth, otelPlugin } from "@kubiks/otel-better-auth";
export const auth = instrumentBetterAuth(betterAuth({
database: db,
plugins: [otelPlugin()], // HTTP-level tracing
// ... your config
}));
// Now direct API calls are also traced:
// await auth.api.getSession({ headers });
```
That's it! All auth operations are now traced automatically.
Instrumenting Better Auth is just a single call—wrap the instance you already
create and every API method invocation is traced automatically. Keep the rest of
your configuration unchanged.
## What Gets Traced
### HTTP-Level (Plugin) - Recommended
The `otelPlugin()` traces all HTTP requests with user ID extraction:
**Authentication:**
- `auth.http.oauth.callback.{provider}` - OAuth callback **with user ID**
- `auth.http.signin.email` - Email signin **with user ID**
- `auth.http.signup.email` - Email signup **with user ID**
@@ -70,29 +44,21 @@ The `otelPlugin()` traces all HTTP requests with user ID extraction:
- `auth.http.get_session` - Get session
**Account & Password:**
- `auth.http.verify_email` - Email verification
- `auth.http.forgot_password` - Password reset request
- `auth.http.reset_password` - Password reset
### Server-Side API Methods (Wrapper)
When using `instrumentBetterAuth()`, **all Better Auth server API methods** are instrumented, including:
**Session Management:**
- `auth.api.get_session` - Get current session with user ID and session ID
- `auth.api.list_sessions` - List all sessions
- `auth.api.revoke_session` - Revoke a session
- `auth.api.revoke_sessions` - Revoke multiple sessions
- `auth.api.revoke_other_sessions` - Revoke all other sessions
**Authentication:**
- `auth.api.signin` (email) - Email signin **with user ID**
- `auth.api.signup` (email) - Email signup **with user ID**
- `auth.api.signin` (social) - OAuth signin **with user ID**
- `auth.api.oauth_callback` - OAuth callback **with user ID**
- `auth.api.signout` - User signout
**Account Management:**
- `auth.api.link_social_account` - Link social account
- `auth.api.unlink_account` - Unlink account
- `auth.api.list_user_accounts` - List user accounts
@@ -100,180 +66,67 @@ When using `instrumentBetterAuth()`, **all Better Auth server API methods** are
- `auth.api.delete_user` - Delete user account
**Password Management:**
- `auth.api.change_password` - Change password
- `auth.api.set_password` - Set password
- `auth.api.forget_password` - Forgot password request
- `auth.api.reset_password` - Reset password
**Email Management:**
- `auth.api.change_email` - Change email
- `auth.api.verify_email` - Verify email **with user ID**
- `auth.api.send_verification_email` - Send verification email
**Token Management:**
- `auth.api.refresh_token` - Refresh access token
- `auth.api.get_access_token` - Get access token
**Plus any other API methods** - The instrumentation automatically wraps all API methods, including those from plugins!
## Span Attributes
Each span includes:
| Attribute | Description | Example |
|-----------|-------------|---------|
| `auth.operation` | Type of operation | `signin`, `signup`, `get_session`, `signout` |
| `auth.method` | Auth method | `email`, `oauth` |
| `auth.provider` | OAuth provider (when applicable) | `google`, `github` |
| `auth.success` | Operation success | `true`, `false` |
| `auth.error` | Error message (when failed) | `Invalid credentials` |
| `user.id` | User ID (when available) | `user_123456` |
| `user.email` | User email (when available) | `user@example.com` |
| `session.id` | Session ID (when available) | `session_abcdef` |
| Attribute | Description | Example |
| ---------------- | -------------------------------- | -------------------------------------------- |
| `auth.operation` | Type of operation | `signin`, `signup`, `get_session`, `signout` |
| `auth.method` | Auth method | `email`, `oauth` |
| `auth.provider` | OAuth provider (when applicable) | `google`, `github` |
| `auth.success` | Operation success | `true`, `false` |
| `auth.error` | Error message (when failed) | `Invalid credentials` |
| `user.id` | User ID (when available) | `user_123456` |
| `user.email` | User email (when available) | `user@example.com` |
| `session.id` | Session ID (when available) | `session_abcdef` |
## Configuration
```typescript
instrumentBetterAuth(authClient, {
tracerName: "my-app-auth", // Custom tracer name
tracer: customTracer, // Custom tracer instance
})
tracerName: "my-app", // Custom tracer name
tracer: customTracer, // Custom tracer instance
});
```
## Examples
### Server-Side with Plugin (Recommended)
### Basic Instrumentation (Auto Plugin)
```typescript
// lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { otelPlugin } from "@kubiks/otel-better-auth";
import { instrumentBetterAuth } from "@kubiks/otel-better-auth";
import { db } from "./db";
export const auth = betterAuth({
baseURL: process.env.BETTER_AUTH_URL,
database: drizzleAdapter(db, { provider: "pg" }),
plugins: [
otelPlugin(), // Traces all HTTP requests including OAuth callbacks
],
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
export const auth = instrumentBetterAuth(
betterAuth({
baseURL: process.env.BETTER_AUTH_URL,
database: drizzleAdapter(db, { provider: "pg" }),
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
},
},
},
});
}),
);
// app/api/auth/[...all]/route.ts
import { auth } from "@/lib/auth";
export { GET, POST } = auth.handler;
```
### Complete Example (Plugin + Wrapper)
For maximum observability, use both approaches:
```typescript
// lib/auth.ts
import { betterAuth } from "better-auth";
import { instrumentBetterAuth, otelPlugin } from "@kubiks/otel-better-auth";
export const auth = instrumentBetterAuth(
betterAuth({
database: db,
plugins: [otelPlugin()], // Traces HTTP requests (OAuth, etc.)
// ... your config
})
);
// Now you get traces for:
// 1. HTTP requests (OAuth callbacks, sign-ins) via otelPlugin
// 2. Direct API calls (auth.api.*) via instrumentBetterAuth
```
### Server API Usage
```typescript
// Server-side route handler
import { auth } from "@/lib/auth";
export async function GET(request: Request) {
// This call is automatically traced with full context
const session = await auth.api.getSession({
headers: request.headers,
});
if (session?.user) {
return Response.json({ user: session.user });
}
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
```
## Trace Examples
### OAuth Sign-In (HTTP Plugin)
When a user signs in with GitHub, you'll see:
```
Span: auth.http.oauth.initiate.github [15ms]
├─ auth.operation: oauth_initiate
├─ auth.method: oauth
├─ auth.provider: github
└─ auth.success: true
Span: auth.http.oauth.callback.github [342ms]
├─ auth.operation: oauth_callback
├─ auth.method: oauth
├─ auth.provider: github
├─ auth.success: true
├─ user.id: user_abc123 ← User ID captured! ✅
├─ user.email: user@github.com
└─ session.id: session_xyz789
```
### Email Sign-In (HTTP Plugin)
```
Span: auth.http.signin.email [245ms]
├─ auth.operation: signin
├─ auth.method: email
├─ auth.success: true
├─ user.id: user_abc123 ← User ID captured! ✅
├─ user.email: user@example.com
└─ session.id: session_xyz789
```
### Direct API Call (Wrapper)
```
Span: auth.api.get_session [12ms]
├─ auth.operation: get_session
├─ auth.success: true
├─ user.id: user_abc123
└─ session.id: session_xyz789
```
## Framework Support
Works with any JavaScript/TypeScript server environment where Better Auth runs:
✅ Next.js (App Router & Pages Router)
✅ Express
✅ Hono
✅ Fastify
✅ SvelteKit
✅ Node.js
✅ Any framework supported by Better Auth
## Related
- [`@kubiks/otel-drizzle`](../otel-drizzle) - OpenTelemetry for Drizzle ORM
- [`better-auth`](https://better-auth.com/) - The authentication library for TypeScript
## License
MIT
+8 -9
View File
@@ -120,7 +120,7 @@ function wrapAuthMethod<T extends (...args: any[]) => Promise<any>>(
span.setStatus({ code: SpanStatusCode.ERROR });
}
} else {
// Handle direct response format (server API)
// Handle direct response format (Better Auth API)
if (result.user?.id) {
span.setAttribute(SEMATTRS_USER_ID, result.user.id);
}
@@ -179,7 +179,7 @@ const API_METHOD_METADATA: Record<
};
/**
* Instruments a Better Auth server instance with OpenTelemetry tracing.
* Instruments a Better Auth instance with OpenTelemetry tracing.
*/
function instrumentServer<O extends Record<string, any> = any>(
server: Auth<O>,
@@ -267,31 +267,30 @@ function ensureOtelPlugin<Options extends BetterAuthInstanceOptions = BetterAuth
}
/**
* Instruments a Better Auth server instance with OpenTelemetry tracing.
* Instruments a Better Auth instance with OpenTelemetry tracing.
*
* This function wraps all server API methods (api.getSession, api.signInEmail, etc.)
* This function wraps all Better Auth API methods (api.getSession, api.signInEmail, etc.)
* to automatically create spans for each auth operation. It captures user IDs,
* session IDs, and auth status in span attributes.
*
* The instrumentation is idempotent - calling it multiple times on the same
* instance will only instrument it once.
*
* @param auth - The Better Auth server instance to instrument
* @param auth - The Better Auth instance to instrument
* @param config - Optional configuration for instrumentation behavior
* @returns The instrumented auth instance (same instance, modified in place)
*
* @example
* ```typescript
* import { betterAuth } from "better-auth";
* import { instrumentBetterAuth, otelPlugin } from "@kubiks/otel-better-auth";
* import { instrumentBetterAuth } from "@kubiks/otel-better-auth";
*
* export const auth = instrumentBetterAuth(betterAuth({
* database: db,
* plugins: [otelPlugin()], // For HTTP-level tracing
* // ... your config
* // ... your Better Auth config
* }));
*
* // Now direct API calls are traced:
* // Direct API calls are traced automatically:
* await auth.api.getSession({ headers });
* ```
*/