StartupKitstartupkit
Auth

Session Management

How sessions work and how to configure them

Sessions track authenticated users across requests. Better Auth handles session storage, cookies, and expiration automatically.

Default Configuration

Out of the box, sessions are configured with:

SettingDefaultDescription
expiresIn7 daysSession duration
updateAge24 hoursHow often to refresh

Sessions refresh automatically when users are active.

How Sessions Work

  1. Sign in: User authenticates via email OTP or OAuth
  2. Create session: Better Auth creates a session record in your database
  3. Set cookie: A secure HTTP-only cookie is sent to the browser
  4. Validate requests: On each request, the cookie is validated against the database
  5. Refresh: Active sessions are automatically extended

Customizing Session Duration

lib/auth.ts
import {  } from "better-auth"

export const  = ({
  // ...
  : {
    : 60 * 60 * 24 * 30,  // 30 days
    : 60 * 60 * 24        // Refresh every 24 hours
  }
})

Common Configurations

Use CaseexpiresInupdateAge
Standard app7 days24 hours
High security1 hour15 minutes
"Remember me"30 days24 hours
Mobile app90 days7 days

Session Storage

Sessions are stored in your database via the Drizzle adapter:

database: (, {
  : "pg",
  : {
    :   // Your sessions table
  }
})

The sessions table stores:

  • id - Unique session ID
  • userId - Associated user
  • token - Session token (in cookie)
  • expiresAt - Expiration timestamp
  • ipAddress - Client IP (optional)
  • userAgent - Browser info (optional)

Accessing Session Data

In Server Components

import {  } from "@/lib/auth"
import {  } from "next/headers"

export default async function () {
  const  = await .api.getSession({
    : await ()
  })

  // session.user - User object
  // session.session - Session metadata
}

In Client Components

"use client"

import {  } from "@startupkit/auth"

export function () {
  const { , ,  } = ()
}

Session Metadata

const  = await .api.getSession({
  : await ()
})

.(.session)
// {
//   id: "session_123",
//   userId: "user_456",
//   expiresAt: Date,
//   ipAddress: "192.168.1.1",
//   userAgent: "Mozilla/5.0..."
// }

Invalidating Sessions

Sign Out Current Session

"use client"

import {  } from "@startupkit/auth"

export function () {
  const {  } = ()

  return < ={}>Sign Out</>
}

Sign Out All Sessions

For "sign out everywhere" functionality:

import {  } from "@/lib/auth"
import {  } from "next/headers"

export async function () {
  const  = await .api.getSession({
    : await ()
  })

  if () {
    // Delete all sessions for this user
    await db.delete(sessions)
      .where(eq(sessions.userId, .user.id))
  }
}

Session Refresh

Sessions automatically refresh when updateAge has passed:

  1. User makes a request
  2. Better Auth checks session age
  3. If older than updateAge, extends expiresAt
  4. User continues without interruption

This ensures active users stay logged in.

Better Auth uses secure HTTP-only cookies:

export const  = ({
  // Cookies are configured automatically, but you can customize:
  : {
    : "myapp",  // Custom cookie prefix
    : {
      : true,
      : ".myapp.com"  // Share across subdomains
    }
  }
})
SettingValue
httpOnlytrue (can't be accessed by JS)
securetrue in production
sameSitelax
path/

Multiple Sessions

Users can have multiple active sessions (different devices):

// Get all sessions for current user
const  = await .()
  .()
  .((.userId, .))

// Display in UI
<>
  {.( => (
    < ={.}>
      {.} - {.}
      < ={() => (.)}>
        Revoke
      </>
    </>
  ))}
</ul>

Security Considerations

IP Address Validation

Track IP for security monitoring:

const  = await .api.getSession({
  : await ()
})

// Check for suspicious IP changes
if (.session.ipAddress !== ) {
  // Log security event
  await ({
    : "SUSPICIOUS_IP_CHANGE",
    : .user.id
  })
}

Force Re-authentication

For sensitive actions, require fresh authentication:

export async function () {
  const  = await .api.getSession({
    : await ()
  })

  // Check when session was created
  const  = .() - .session.createdAt.getTime()
  const  = 15 * 60 * 1000

  if ( > ) {
    throw new ("Please re-authenticate for this action")
  }

  // Proceed with sensitive action
}

Debugging Sessions

Check Session in Database

SELECT * FROM "Session" WHERE "userId" = 'user_123';

Log Session Events

export const  = ({
  : {
    : async () => {
      if (.newSession) {
        .("New session created:", .newSession.id)
      }
    }
  }
})

Next Steps

On this page