Overview @kubiks/otel-better-auth provides comprehensive OpenTelemetry instrumentation for Better Auth . Get complete authentication observability across all auth flows with a single line of code—OAuth, email/password, sessions, account management, and more.Visualize your authentication flows with detailed span information including operation type, user IDs, session IDs, auth methods, and success/failure status. 
Installation npm  install  @kubiks/otel-better-auth 
Peer Dependencies:  @opentelemetry/api >= 1.9.0, better-auth >= 1.0.0
Quick Start import  {  betterAuth  }  from  "better-auth" ; import  {  instrumentBetterAuth  }  from  "@kubiks/otel-better-auth" ; export  const  auth  =  instrumentBetterAuth (   betterAuth ({     database:  db ,     // ... your Better Auth config   }), ); 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. 
Traced Operations  Authentication
 Session Management
 Account Management
 Password & Email
Sign In & Sign Up: 
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 auth.http.oauth.initiate.{provider} - OAuth initiationauth.http.signout - User signoutauth.http.get_session - Get session Span Attributes Each span includes rich context about the authentication operation: 
Attribute Description Example auth.operationType of operation signin, signup, get_session, signoutauth.methodAuth method email, oauthauth.providerOAuth provider (when applicable) google, githubauth.successOperation success true, falseauth.errorError message (when failed) Invalid credentialsuser.idUser ID (when available) user_123456user.emailUser email (when available) user@example.comsession.idSession ID (when available) session_abcdef
User IDs and session IDs are captured where applicable to help with debugging and monitoring authentication flows. 
Configuration You can optionally customize the instrumentation: 
instrumentBetterAuth ( authClient , {   tracerName:  "my-app" ,  // Custom tracer name   tracer:  customTracer ,  // Custom tracer instance }); Usage Examples Basic Setup (Next.js App Router) 
Configure Better Auth
import  {  betterAuth  }  from  "better-auth" ; import  {  drizzleAdapter  }  from  "better-auth/adapters/drizzle" ; import  {  instrumentBetterAuth  }  from  "@kubiks/otel-better-auth" ; import  {  db  }  from  "./db" ; 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 ,       },       google:  {         clientId:  process . env . GOOGLE_CLIENT_ID ,         clientSecret:  process . env . GOOGLE_CLIENT_SECRET ,       },     },   }), ); 
Create Auth Handler
app/api/auth/[...all]/route.ts
import  {  auth  }  from  "@/lib/auth" ; export  const  {  GET ,  POST  }  =  auth . handler ; 
Use in Your App
All authentication operations are now automatically traced! // Sign in await  auth . api . signInEmail ({   email:  "user@example.com" ,   password:  "password" , }); // Get session const  session  =  await  auth . api . getSession (); OAuth Authentication GitHub OAuth
Google OAuth
Multiple Providers
export  const  auth  =  instrumentBetterAuth (   betterAuth ({     database:  db ,     socialProviders:  {       github:  {         clientId:  process . env . GITHUB_CLIENT_ID ,         clientSecret:  process . env . GITHUB_CLIENT_SECRET ,       },     },   }), ); // OAuth callback is automatically traced with provider name // Span: auth.http.oauth.callback.github 
Email/Password Authentication "use server" ; import  {  auth  }  from  "@/lib/auth" ; export  async  function  signUp ( email :  string ,  password :  string ,  name :  string ) {   const  result  =  await  auth . api . signUpEmail ({     email ,     password ,     name ,   });   // Traced as: auth.http.signup.email   // Includes: user.id, user.email, auth.success   return  result ; } 
Session Management Get Session
List Sessions
Revoke Session
Revoke Other Sessions
"use server" ; import  {  auth  }  from  "@/lib/auth" ; export  async  function  getCurrentSession () {   const  session  =  await  auth . api . getSession ();      // Traced as: auth.api.get_session   // Includes: user.id, session.id, auth.success      return  session ; } 
Account Management Update Profile
Link Social Account
Delete Account
"use server" ; import  {  auth  }  from  "@/lib/auth" ; export  async  function  updateProfile ( name :  string ,  image ?:  string ) {   const  result  =  await  auth . api . updateUser ({     name ,     image ,   });   // Traced as: auth.api.update_user   // Includes: user.id, auth.success   return  result ; } 
Password Management Change Password
Reset Password
"use server" ; import  {  auth  }  from  "@/lib/auth" ; export  async  function  changePassword (   currentPassword :  string ,   newPassword :  string ) {   const  result  =  await  auth . api . changePassword ({     currentPassword ,     newPassword ,   });   // Traced as: auth.api.change_password   // Includes: user.id, auth.success   return  result ; } 
Email Management "use server" ; import  {  auth  }  from  "@/lib/auth" ; export  async  function  verifyEmail ( token :  string ) {   const  result  =  await  auth . api . verifyEmail ({  token  });   // Traced as: auth.api.verify_email   // Includes: user.id, user.email, auth.success   return  result ; } 
Complete Integration Example Here’s a full example of Better Auth with OpenTelemetry in a Next.js application: 
import  {  betterAuth  }  from  "better-auth" ; import  {  drizzleAdapter  }  from  "better-auth/adapters/drizzle" ; import  {  instrumentBetterAuth  }  from  "@kubiks/otel-better-auth" ; import  {  db  }  from  "./db" ; export  const  auth  =  instrumentBetterAuth (   betterAuth ({     baseURL:  process . env . BETTER_AUTH_URL ! ,     database:  drizzleAdapter ( db , {  provider:  "pg"  }),          emailAndPassword:  {       enabled:  true ,       requireEmailVerification:  true ,     },          socialProviders:  {       github:  {         clientId:  process . env . GITHUB_CLIENT_ID ! ,         clientSecret:  process . env . GITHUB_CLIENT_SECRET ! ,       },       google:  {         clientId:  process . env . GOOGLE_CLIENT_ID ! ,         clientSecret:  process . env . GOOGLE_CLIENT_SECRET ! ,       },     },          session:  {       expiresIn:  60  *  60  *  24  *  7 ,  // 1 week       updateAge:  60  *  60  *  24 ,  // 1 day     },   }),   {     tracerName:  "my-app-auth" ,   } ); app/api/auth/[...all]/route.ts
import  {  auth  }  from  "@/lib/auth" ; export  const  {  GET ,  POST  }  =  auth . handler ; "use server" ; import  {  auth  }  from  "@/lib/auth" ; import  {  redirect  }  from  "next/navigation" ; export  async  function  signInWithEmail ( email :  string ,  password :  string ) {   const  result  =  await  auth . api . signInEmail ({     email ,     password ,   });   if  ( ! result . error ) {     redirect ( "/dashboard" );   }   return  result ; } export  async  function  signUpWithEmail (   email :  string ,   password :  string ,   name :  string ) {   const  result  =  await  auth . api . signUpEmail ({     email ,     password ,     name ,   });   if  ( ! result . error ) {     redirect ( "/verify-email" );   }   return  result ; } export  async  function  signOut () {   await  auth . api . signOut ();   redirect ( "/" ); } Best Practices 
Always use Server Actions for authentication operations in Next.js: "use server" ; import  {  auth  }  from  "@/lib/auth" ; export  async  function  signIn ( email :  string ,  password :  string ) {   return  await  auth . api . signInEmail ({  email ,  password  }); } 
Check for errors and provide appropriate feedback: const  result  =  await  auth . api . signInEmail ({  email ,  password  }); if  ( result . error ) {   return  {  error:  result . error . message  }; } return  {  success:  true  }; 
Always enable email verification for production: betterAuth ({   emailAndPassword:  {     enabled:  true ,     requireEmailVerification:  true ,   }, }) 
Use descriptive tracer names for easier debugging: instrumentBetterAuth ( auth , {   tracerName:  "my-app-auth" , }); Troubleshooting 
Ensure OpenTelemetry is properly initialized before creating the auth instance: import  {  NodeSDK  }  from  "@opentelemetry/sdk-node" ; const  sdk  =  new  NodeSDK ({   // ... configuration }); sdk . start (); // Then create auth instance export  const  auth  =  instrumentBetterAuth ( betterAuth ({  ...  })); 
User IDs are only captured for operations where the user is authenticated. For sign-in and sign-up, the user ID is captured after successful authentication. 
OAuth Provider Not Traced
Make sure you’re using the correct provider name in your Better Auth configuration. The provider name must match exactly (e.g., github, not GitHub). 
Resources License MIT