mirror of
https://github.com/zoriya/drizzle-otel.git
synced 2026-06-02 19:11:32 +00:00
update docs
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 });
|
||||
* ```
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user