세션 관리
Better Auth는 전통적인 쿠키 기반 세션 관리를 사용하여 세션을 관리합니다. 세션은 쿠키에 저장되며 모든 요청마다 서버로 전송됩니다. 그런 다음 서버가 세션을 검증하고 세션이 유효한 경우 사용자 데이터를 반환합니다.
세션 테이블
세션 테이블은 세션 데이터를 저장합니다. 세션 테이블에는 다음 필드가 있습니다:
id: 세션 토큰. 세션 쿠키로도 사용됩니다.userId: 사용자의 사용자 ID.expiresAt: 세션의 만료 날짜.ipAddress: 사용자의 IP 주소.userAgent: 사용자의 user agent. 요청의 user agent 헤더를 저장합니다.
세션 만료
세션은 기본적으로 7일 후에 만료됩니다. 그러나 세션이 사용되고 updateAge에 도달할 때마다 세션 만료가 현재 시간에 expiresIn 값을 더한 값으로 업데이트됩니다.
auth 설정에 session 객체를 전달하여 expiresIn과 updateAge 값을 모두 변경할 수 있습니다.
import { betterAuth } from "better-auth"
export const auth = betterAuth({
//... 기타 설정 옵션
session: {
expiresIn: 60 * 60 * 24 * 7, // 7일
updateAge: 60 * 60 * 24 // 1일 (1일마다 세션 만료가 업데이트됨)
}
})세션 새로고침 비활성화
updateAge 옵션에 관계없이 세션이 업데이트되지 않도록 세션 새로고침을 비활성화할 수 있습니다.
import { betterAuth } from "better-auth"
export const auth = betterAuth({
//... 기타 설정 옵션
session: {
disableSessionRefresh: true
}
})세션 신선도
Better Auth의 일부 엔드포인트는 세션이 신선해야 합니다. 세션은 createdAt이 freshAge 제한 내에 있으면 신선한 것으로 간주됩니다. 기본적으로 freshAge는 1일 (60 * 60 * 24)로 설정됩니다.
auth 설정에서 session 객체를 전달하여 freshAge 값을 커스터마이징할 수 있습니다:
import { betterAuth } from "better-auth"
export const auth = betterAuth({
//... 기타 설정 옵션
session: {
freshAge: 60 * 5 // 5분 (지난 5분 내에 생성된 경우 세션이 신선함)
}
})신선도 확인을 비활성화하려면 freshAge를 0으로 설정하세요:
import { betterAuth } from "better-auth"
export const auth = betterAuth({
//... 기타 설정 옵션
session: {
freshAge: 0 // 신선도 확인 비활성화
}
})세션 관리
Better Auth는 세션을 관리하는 함수 세트를 제공합니다.
세션 가져오기
getSession 함수는 현재 활성 세션을 가져옵니다.
import { authClient } from "@/lib/client"
const { data: session } = await authClient.getSession()세션 응답을 커스터마이징하는 방법을 알아보려면 세션 응답 커스터마이징 섹션을 확인하세요.
Use Session
useSession 액션은 현재 세션에 접근하는 반응형 방법을 제공합니다.
import { authClient } from "@/lib/client"
const { data: session } = authClient.useSession()세션 나열
listSessions 함수는 사용자에 대해 활성화된 세션 목록을 반환합니다.
import { authClient } from "@/lib/client"
const sessions = await authClient.listSessions()세션 취소
사용자가 기기에서 로그아웃하면 세션이 자동으로 종료됩니다. 그러나 사용자가 로그인한 모든 기기에서 수동으로 세션을 종료할 수도 있습니다.
세션을 종료하려면 revokeSession 함수를 사용하세요. 매개변수로 세션 토큰을 전달하기만 하면 됩니다.
await authClient.revokeSession({
token: "session-token"
})다른 세션 취소
현재 세션을 제외한 다른 모든 세션을 취소하려면 revokeOtherSessions 함수를 사용할 수 있습니다.
await authClient.revokeOtherSessions()모든 세션 취소
모든 세션을 취소하려면 revokeSessions 함수를 사용할 수 있습니다.
await authClient.revokeSessions()비밀번호 변경 시 세션 취소
changePassword 함수에서 revokeOtherSessions를 true로 전달하여 사용자가 비밀번호를 변경할 때 모든 세션을 취소할 수 있습니다.
await authClient.changePassword({
newPassword: newPassword,
currentPassword: currentPassword,
revokeOtherSessions: true,
})세션 캐싱
쿠키 캐시
useSession이나 getSession이 호출될 때마다 데이터베이스를 호출하는 것은 이상적이지 않습니다. 특히 세션이 자주 변경되지 않는 경우에는 더욱 그렇습니다. 쿠키 캐싱은 세션 데이터를 단기 수명의 서명된 쿠키에 저장하여 이를 처리합니다. 이는 refresh 토큰과 함께 JWT access 토큰을 사용하는 방식과 유사합니다.
쿠키 캐싱이 활성화되면 서버는 매번 데이터베이스를 조회하는 대신 쿠키 자체에서 세션 유효성을 확인할 수 있습니다. 쿠키는 변조를 방지하기 위해 서명되며, 짧은 maxAge는 세션 데이터가 정기적으로 새로고침되도록 보장합니다. 세션이 취소되거나 만료되면 쿠키가 자동으로 무효화됩니다.
쿠키 캐싱을 활성화하려면 auth 설정에서 session.cookieCache를 설정하기만 하면 됩니다:
import { betterAuth } from "better-auth"
export const auth = betterAuth({
session: {
cookieCache: {
enabled: true,
maxAge: 5 * 60 // 초 단위 캐시 지속 시간
}
}
});세션을 가져올 때 쿠키 캐시에서 반환하는 것을 비활성화하려면 disableCookieCache:true를 전달할 수 있습니다. 이렇게 하면 서버가 데이터베이스에서 세션을 가져오고 쿠키 캐시도 새로고침합니다.
const session = await authClient.getSession({ query: {
disableCookieCache: true
}})또는 서버에서
await auth.api.getSession({
query: {
disableCookieCache: true,
},
headers: req.headers, // 헤더 전달
});세션 응답 커스터마이징
getSession이나 useSession을 호출하면 세션 데이터가 user와 session 객체로 반환됩니다. customSession 플러그인을 사용하여 이 응답을 커스터마이징할 수 있습니다.
import { customSession } from "better-auth/plugins";
export const auth = betterAuth({
plugins: [
customSession(async ({ user, session }) => {
const roles = findUserRoles(session.session.userId);
return {
roles,
user: {
...user,
newField: "newField",
},
session
};
}),
],
});이렇게 하면 세션 응답에 roles와 user.newField가 추가됩니다.
클라이언트에서 추론
import { customSessionClient } from "better-auth/client/plugins";
import type { auth } from "@/lib/auth"; // auth 인스턴스를 타입으로 가져오기
const authClient = createAuthClient({
plugins: [customSessionClient<typeof auth>()],
});
const { data } = authClient.useSession();
const { data: sessionData } = await authClient.getSession();
// data.roles
// data.user.newField세션 응답 커스터마이징 시 주의사항
- 콜백에 전달된
session객체는 플러그인이 추가한 필드를 추론하지 않습니다.
그러나 해결 방법으로 auth 옵션을 가져와서 플러그인에 전달하여 필드를 추론할 수 있습니다.
import { betterAuth, BetterAuthOptions } from "better-auth";
const options = {
//...설정 옵션
plugins: [
//...플러그인
]
} satisfies BetterAuthOptions;
export const auth = betterAuth({
...options,
plugins: [
...(options.plugins ?? []),
customSession(async ({ user, session }, ctx) => {
// 이제 user와 session 모두 플러그인이 추가한 필드와 커스텀 필드를 추론합니다
return {
user,
session
}
}, options), // 여기에 옵션 전달
]
})- 서버와 클라이언트 코드가 별도의 프로젝트나 저장소에 있고
auth인스턴스를 타입 참조로 가져올 수 없는 경우, 커스텀 세션 필드에 대한 타입 추론이 클라이언트 측에서 작동하지 않습니다. - 보조 스토리지나 쿠키 캐시를 포함한 세션 캐싱에는 커스텀 필드가 포함되지 않습니다. 세션을 가져올 때마다 커스텀 세션 함수가 호출됩니다.
list-device-sessions 엔드포인트 변형
multi-session 플러그인의 /multi-session/list-device-sessions 엔드포인트는 사용자가 로그인한 기기를 나열하는 데 사용됩니다.
customSession 플러그인에 shouldMutateListDeviceSessionsEndpoint 옵션을 전달하여 이 엔드포인트의 응답을 변형할 수 있습니다.
기본적으로 이 엔드포인트의 응답을 변형하지 않습니다.
import { customSession } from "better-auth/plugins";
export const auth = betterAuth({
plugins: [
customSession(async ({ user, session }, ctx) => {
return {
user,
session
}
}, {}, { shouldMutateListDeviceSessionsEndpoint: true }),
],
});