Overview
The user endpoint returns detailed information about the currently authenticated user, including their profile data, email verification status, and account metadata.
Endpoint
This endpoint requires authentication via session cookie
Request
Using Hono RPC Client
import { apiClient } from "@/lib/api/client"
const response = await apiClient . v1 . user . $get ()
const { data } = await response . json ()
console . log ( data )
// {
// id: "iO8PZYiiwR6e0o9XDtqyAmUemv1Pc8tc",
// email: "[email protected] ",
// name: "John Doe",
// emailVerified: true,
// ...
// }
Using Fetch
const response = await fetch ( 'https://your-domain.com/api/v1/user' , {
method: 'GET' ,
credentials: 'include' , // Required for cookie-based auth
})
if ( ! response . ok ) {
throw new Error ( 'Authentication required' )
}
const { data } = await response . json ()
Using cURL
curl https://your-domain.com/api/v1/user \
-H "Cookie: session_token=your_session_token" \
-X GET
Response
Success Response (200 OK)
The user object Unique user identifier Example: "iO8PZYiiwR6e0o9XDtqyAmUemv1Pc8tc"
User’s display name Example: "John Doe"
Whether the user’s email address has been verified Example: true
URL to the user’s profile image (null if not set) Example: "https://example.com/avatar.png"
ISO 8601 timestamp when the user account was created Format: date-timeExample: "2025-12-17T14:33:40.317Z"
ISO 8601 timestamp when the user account was last updated Format: date-timeExample: "2025-12-17T14:33:40.317Z"
Response Schema
interface UserResponse {
data : {
id : string
email : string
name : string
emailVerified : boolean
image : string | null
createdAt : string // ISO 8601 date-time
updatedAt : string // ISO 8601 date-time
}
}
Example Response
{
"data" : {
"id" : "iO8PZYiiwR6e0o9XDtqyAmUemv1Pc8tc" ,
"email" : "[email protected] " ,
"name" : "John Doe" ,
"emailVerified" : true ,
"image" : "https://avatars.githubusercontent.com/u/12345678" ,
"createdAt" : "2025-12-17T14:33:40.317Z" ,
"updatedAt" : "2025-12-17T14:33:40.317Z"
}
}
Error Response (401 Unauthorized)
Returned when the session is invalid, expired, or missing:
{
"error" : {
"code" : "UNAUTHORIZED" ,
"message" : "Authentication required"
}
}
Implementation
The user endpoint is defined in api/hono/src/routers/v1.ts:
api/hono/src/routers/v1.ts
const userSchema = z . object ({
createdAt: z . string (). meta ({ format: "date-time" , example: "2025-12-17T14:33:40.317Z" }),
email: z . string (). meta ({ example: "[email protected] " }),
emailVerified: z . boolean (). meta ({ example: true }),
id: z . string (). meta ({ example: "iO8PZYiiwR6e0o9XDtqyAmUemv1Pc8tc" }),
image: z . string (). nullable (). meta ({ example: "https://example.com/avatar.png" }),
name: z . string (). meta ({ example: "John Doe" }),
updatedAt: z . string (). meta ({ format: "date-time" , example: "2025-12-17T14:33:40.317Z" }),
})
export const v1Router = new Hono <{
Variables : Session
}>()
. use ( "/*" , authMiddleware )
. get (
"/user" ,
describeRoute ({
tags: [ "v1" ],
description: "Get current user only" ,
responses: {
200 : {
description: "OK" ,
content: {
"application/json" : {
schema: resolver ( z . object ({ data: userSchema })),
},
},
},
},
}),
( c ) => {
const data = c . get ( "user" )
return c . json ({ data })
},
)
Authentication Middleware
The authMiddleware validates the session and injects the user into the request context:
Extracts the session token from the HTTP-only cookie
Validates the session with Better Auth
Retrieves the user from the database
Injects the user into the Hono context as c.get("user")
Returns 401 Unauthorized if validation fails
Use Cases
User Profile Display user information in the application header or profile page
Personalization Customize the user experience based on user data
Email Verification Check if the user needs to verify their email
Avatar Display Show the user’s profile image in the UI
React Hook Example
Create a custom hook to fetch user data:
import { apiClient } from "@/lib/api/client"
import { useQuery } from "@tanstack/react-query"
export function useUser () {
return useQuery ({
queryKey: [ "user" ],
queryFn : async () => {
const response = await apiClient . v1 . user . $get ()
if ( ! response . ok ) {
throw new Error ( "Failed to fetch user" )
}
const { data } = await response . json ()
return data
},
staleTime: 5 * 60 * 1000 , // 5 minutes
})
}
Usage in a component:
components/user-profile.tsx
import { useUser } from "@/hooks/use-user"
import { Avatar } from "@/components/ui/avatar"
export function UserProfile () {
const { data : user , isLoading } = useUser ()
if ( isLoading ) return < div > Loading... </ div >
return (
< div className = "flex items-center gap-3" >
< Avatar src = { user . image } alt = { user . name } />
< div >
< h3 className = "font-semibold" > { user . name } </ h3 >
< p className = "text-sm text-muted-foreground" > { user . email } </ p >
{ ! user . emailVerified && (
< p className = "text-xs text-amber-600" > Email not verified </ p >
) }
</ div >
</ div >
)
}
Server Component Example
In Next.js App Router, fetch user data in a Server Component:
import { apiClient } from "@/lib/api/client"
import { cookies } from "next/headers"
async function getUser () {
const response = await apiClient . v1 . user . $get ()
if ( ! response . ok ) {
throw new Error ( "Authentication required" )
}
const { data } = await response . json ()
return data
}
export default async function DashboardPage () {
const user = await getUser ()
return (
< div >
< h1 > Welcome, { user . name } ! </ h1 >
< p > Email: { user . email } </ p >
</ div >
)
}
Email Verification Check
Check if the user needs to verify their email:
utils/check-email-verified.ts
import { apiClient } from "@/lib/api/client"
export async function requireEmailVerification () {
const response = await apiClient . v1 . user . $get ()
if ( ! response . ok ) {
throw new Error ( "Authentication required" )
}
const { data : user } = await response . json ()
if ( ! user . emailVerified ) {
// Redirect to email verification page
window . location . href = "/verify-email"
return false
}
return true
}
Type Safety with Hono RPC
The Hono RPC client provides full type safety:
import { apiClient } from "@/lib/api/client"
// TypeScript knows the exact shape of the response
const response = await apiClient . v1 . user . $get ()
const { data } = await response . json ()
// Full IntelliSense for user properties
data . id // string
data . email // string
data . name // string
data . image // string | null
data . emailVerified // boolean
data . createdAt // string
data . updatedAt // string
User Type Definition
Extract the user type from the API:
import type { InferResponseType } from "hono/client"
import type { apiClient } from "@/lib/api/client"
type UserResponse = InferResponseType < typeof apiClient . v1 . user . $get >
export type User = UserResponse [ "data" ]
Caching Strategy
Recommended caching strategy for user data:
import { apiClient } from "@/lib/api/client"
import { queryOptions } from "@tanstack/react-query"
export const userQueryOptions = queryOptions ({
queryKey: [ "user" ],
queryFn : async () => {
const response = await apiClient . v1 . user . $get ()
if ( ! response . ok ) throw new Error ( "Failed to fetch user" )
const { data } = await response . json ()
return data
},
staleTime: 5 * 60 * 1000 , // 5 minutes
gcTime: 10 * 60 * 1000 , // 10 minutes
})
Session API Get the current session information
Better Auth Learn about authentication endpoints
Next Steps
Session Endpoint Learn how to fetch session data
Authentication Understand the authentication system
API Overview Explore the complete API reference