API Key
API Key 플러그인을 사용하면 애플리케이션의 API 키를 생성하고 관리할 수 있습니다. API 키를 검증하여 API 요청을 인증하고 권한을 부여하는 방법을 제공합니다.
기능
- API 키 생성, 관리 및 검증
- 내장 속도 제한
- 사용자 정의 만료 시간, 남은 횟수 및 재충전 시스템
- API 키 메타데이터
- 사용자 정의 접두사
- API 키로부터 세션 생성
설치
서버에 플러그인 추가하기
import { betterAuth } from "better-auth"
import { apiKey } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
apiKey()
]
})데이터베이스 마이그레이션
마이그레이션을 실행하거나 스키마를 생성하여 필요한 필드와 테이블을 데이터베이스에 추가합니다.
npx @better-auth/cli migratenpx @better-auth/cli generate필드를 수동으로 추가하려면 Schema 섹션을 참조하세요.
클라이언트 플러그인 추가하기
import { createAuthClient } from "better-auth/client"
import { apiKeyClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [
apiKeyClient()
]
})사용법
API Key 플러그인 옵션 목록은 여기에서 확인할 수 있습니다.
API 키 생성하기
서버 메서드를 사용하여 더 구체적인 API 키 설정을 조정할 수 있습니다.
const { data, error } = await authClient.apiKey.create({ name: 'project-api-key', expiresIn: 60 * 60 * 24 * 7, prefix: 'project-api-key', metadata: { someKey: 'someValue' }, permissions,});| Prop | Description | Type |
|---|---|---|
name? | API 키의 이름입니다. | string |
expiresIn? | API 키의 만료 시간(초)입니다. | number |
prefix? | API 키의 접두사입니다. | string |
metadata? | API 키의 메타데이터입니다. | any | null |
permissions? | API 키의 권한입니다. | Record<string, string[]> |
결과
key 값을 포함하는 ApiKey 객체를 반환합니다.
실패할 경우 APIError를 던집니다.
API 키 검증하기
const permissions = { // 확인할 권한은 선택 사항입니다. projects: ["read", "read-write"],}const data = await auth.api.verifyApiKey({ body: { key: "your_api_key_here", // required permissions, },});| Prop | Description | Type |
|---|---|---|
key | 검증할 키입니다. | string |
permissions? | 검증할 권한입니다. 선택 사항입니다. | Record<string, string[]> |
결과
type Result = {
valid: boolean;
error: { message: string; code: string } | null;
key: Omit<ApiKey, "key"> | null;
};API 키 가져오기
const { data, error } = await authClient.apiKey.get({ id: "some-api-key-id", // required});| Prop | Description | Type |
|---|---|---|
id | API 키의 ID입니다. | string |
결과
key 값 자체를 제외한 API 키 세부 정보를 모두 받습니다.
실패할 경우 APIError를 던집니다.
type Result = Omit<ApiKey, "key">;API 키 업데이트하기
const { data, error } = await authClient.apiKey.update({ keyId: "some-api-key-id", // required name: "some-api-key-name",});| Prop | Description | Type |
|---|---|---|
keyId | 업데이트할 API 키의 ID입니다. | string |
name? | 키의 이름입니다. | string |
결과
실패할 경우 APIError를 던집니다.
성공할 경우 key 값 자체를 제외한 API 키 세부 정보를 받습니다.
API 키 삭제하기
이 엔드포인트는 사용자의 관점에서 API 키를 삭제하려고 시도합니다. 사용자의 ID가 키 소유자와 일치하는지 확인하여 삭제할 수 있습니다. 이러한 검사 없이 키를 삭제하려면 ORM을 사용하여 DB를 직접 변경하는 것을 권장합니다.
const { data, error } = await authClient.apiKey.delete({ keyId: "some-api-key-id", // required});| Prop | Description | Type |
|---|---|---|
keyId | 삭제할 API 키의 ID입니다. | string |
결과
실패할 경우 APIError를 던집니다.
성공할 경우 다음을 받습니다:
type Result = {
success: boolean;
};API 키 목록 조회하기
const { data, error } = await authClient.apiKey.list();결과
실패할 경우 APIError를 던집니다.
성공할 경우 다음을 받습니다:
type Result = ApiKey[];만료된 모든 API 키 삭제하기
이 함수는 만료일이 지난 모든 API 키를 삭제합니다.
const data = await auth.api.deleteAllExpiredApiKeys();만료된 API 키는 apiKey 플러그인 엔드포인트가 호출될 때마다 자동으로 삭제됩니다. 다만, 데이터베이스에 대한 여러 호출을 방지하기 위해 각 호출마다 10초의 쿨다운 시간이 적용됩니다.
API 키로부터 세션 생성하기
Better Auth의 엔드포인트가 헤더에 유효한 API 키와 함께 호출될 때마다 sessionForAPIKeys 옵션을 활성화하여 사용자를 나타내는 모의 세션을 자동으로 생성할 수 있습니다.
이는 일반적으로 권장되지 않습니다. 주의해서 사용하지 않으면 보안 문제가 발생할 수 있습니다. 유출된 API 키는 사용자를 가장하는 데 사용될 수 있습니다.
export const auth = betterAuth({
plugins: [
apiKey({
sessionForAPIKeys: true,
}),
],
});const session = await auth.api.getSession({
headers: new Headers({
'x-api-key': apiKey,
}),
});기본 헤더 키는 x-api-key이지만, 플러그인 옵션의 apiKeyHeaders 옵션을 설정하여 변경할 수 있습니다.
export const auth = betterAuth({
plugins: [
apiKey({
apiKeyHeaders: ["x-api-key", "xyz-api-key"], // 또는 문자열만 전달할 수 있습니다. 예: "x-api-key"
}),
],
});또는 선택적으로 플러그인 옵션에 apiKeyGetter 함수를 전달할 수 있습니다. 이 함수는 GenericEndpointContext와 함께 호출되며, 여기서 API 키를 반환하거나 요청이 유효하지 않은 경우 null을 반환해야 합니다.
export const auth = betterAuth({
plugins: [
apiKey({
apiKeyGetter: (ctx) => {
const has = ctx.request.headers.has("x-api-key");
if (!has) return null;
return ctx.request.headers.get("x-api-key");
},
}),
],
});속도 제한
모든 API 키는 자체적인 속도 제한 설정을 가질 수 있지만, 내장 속도 제한은 주어진 API 키에 대한 검증 프로세스에만 적용됩니다. 다른 모든 엔드포인트/메서드의 경우 Better Auth의 내장 속도 제한을 활용해야 합니다.
아래 API Key 플러그인 옵션에서 속도 제한 기본 설정을 참조할 수 있습니다.
기본값 예시:
export const auth = betterAuth({
plugins: [
apiKey({
rateLimit: {
enabled: true,
timeWindow: 1000 * 60 * 60 * 24, // 1일
maxRequests: 10, // 하루에 10개의 요청
},
}),
],
});각 API 키에 대해 생성 시 속도 제한 옵션을 사용자 정의할 수 있습니다.
서버 auth 인스턴스에서만 속도 제한 옵션을 사용자 정의할 수 있습니다.
const apiKey = await auth.api.createApiKey({
body: {
rateLimitEnabled: true,
rateLimitTimeWindow: 1000 * 60 * 60 * 24, // 1일
rateLimitMax: 10, // 하루에 10개의 요청
},
headers: user_headers,
});작동 방식
각 요청마다 카운터(내부적으로 requestCount라고 함)가 증가합니다.
rateLimitMax에 도달하면 timeWindow가 지날 때까지 요청이 거부되며, 그 후 timeWindow가 재설정됩니다.
남은 횟수, 재충전 및 만료
남은 횟수는 API 키가 비활성화되기 전까지 남은 요청 수입니다.
재충전 간격은 remaining 횟수가 일별로 재충전되는 간격(밀리초)입니다.
만료 시간은 API 키의 만료일입니다.
작동 방식
남은 횟수:
API 키가 사용될 때마다 remaining 횟수가 업데이트됩니다.
remaining 횟수가 null이면 키 사용에 제한이 없습니다.
그렇지 않으면 remaining 횟수가 1씩 감소합니다.
remaining 횟수가 0이면 API 키가 비활성화되고 제거됩니다.
refillInterval 및 refillAmount:
API 키가 생성될 때 refillInterval과 refillAmount는 null로 설정됩니다.
이는 API 키가 자동으로 재충전되지 않음을 의미합니다.
그러나 refillInterval과 refillAmount가 설정되면 API 키가 그에 따라 재충전됩니다.
만료:
API 키가 생성될 때 expiresAt은 null로 설정됩니다.
이는 API 키가 만료되지 않음을 의미합니다.
그러나 expiresIn이 설정되면 API 키는 expiresIn 시간 후에 만료됩니다.
사용자 정의 키 생성 및 검증
플러그인 옵션에서 직접 키 생성 및 검증 프로세스를 사용자 정의할 수 있습니다.
예시:
export const auth = betterAuth({
plugins: [
apiKey({
customKeyGenerator: (options: {
length: number;
prefix: string | undefined;
}) => {
const apiKey = mySuperSecretApiKeyGenerator(
options.length,
options.prefix
);
return apiKey;
},
customAPIKeyValidator: async ({ ctx, key }) => {
const res = await keyService.verify(key)
return res.valid
},
}),
],
});customKeyGenerator에서 제공하는 length 속성을 사용하지 않는 경우 생성될 키의 길이를 defaultKeyLength 속성으로 반드시 설정해야 합니다.
export const auth = betterAuth({
plugins: [
apiKey({
customKeyGenerator: () => {
return crypto.randomUUID();
},
defaultKeyLength: 36, // 또는 해당 길이
}),
],
});API 키가 customAPIKeyValidator에서 검증되면, 데이터베이스의 키와 여전히 일치시켜야 합니다.
그러나 이 사용자 정의 함수를 제공하면 API 키 검증 프로세스의 성능을 향상시킬 수 있습니다.
실패한 모든 키는 데이터베이스를 쿼리하지 않고도 무효화될 수 있기 때문입니다.
메타데이터
API 키와 함께 메타데이터를 저장할 수 있습니다. 이는 예를 들어 구독 플랜과 같은 키에 대한 정보를 저장하는 데 유용합니다.
메타데이터를 저장하려면 플러그인 옵션에서 메타데이터 기능을 비활성화하지 않았는지 확인하세요.
export const auth = betterAuth({
plugins: [
apiKey({
enableMetadata: true,
}),
],
});그런 다음 API 키 객체의 metadata 필드에 메타데이터를 저장할 수 있습니다.
const apiKey = await auth.api.createApiKey({
body: {
metadata: {
plan: "premium",
},
},
});그런 다음 API 키 객체에서 메타데이터를 검색할 수 있습니다.
const apiKey = await auth.api.getApiKey({
body: {
keyId: "your_api_key_id_here",
},
});
console.log(apiKey.metadata.plan); // "premium"API Key 플러그인 옵션
apiKeyHeaders string | string[];
API 키를 확인할 헤더 이름입니다. 기본값은 x-api-key입니다.
customAPIKeyGetter (ctx: GenericEndpointContext) => string | null
컨텍스트에서 API 키를 가져오는 사용자 정의 함수입니다.
customAPIKeyValidator (options: { ctx: GenericEndpointContext; key: string; }) => boolean | Promise<boolean>
API 키를 검증하는 사용자 정의 함수입니다.
customKeyGenerator (options: { length: number; prefix: string | undefined; }) => string | Promise<string>
API 키를 생성하는 사용자 정의 함수입니다.
startingCharactersConfig { shouldStore?: boolean; charactersLength?: number; }
시작 문자 설정을 사용자 정의합니다.
defaultKeyLength number
API 키의 길이입니다. 길수록 좋습니다. 기본값은 64입니다. (접두사 길이 제외)
defaultPrefix string
API 키의 접두사입니다.
참고: 접두사를 더 식별하기 쉽게 만들기 위해 접두사에 밑줄을 추가하는 것을 권장합니다. (예: hello_)
maximumPrefixLength number
접두사의 최대 길이입니다.
minimumPrefixLength number
접두사의 최소 길이입니다.
requireName boolean
API 키에 이름이 필요한지 여부입니다. 기본값은 false입니다.
maximumNameLength number
이름의 최대 길이입니다.
minimumNameLength number
이름의 최소 길이입니다.
enableMetadata boolean
API 키에 메타데이터를 활성화할지 여부입니다.
keyExpiration { defaultExpiresIn?: number | null; disableCustomExpiresTime?: boolean; minExpiresIn?: number; maxExpiresIn?: number; }
키 만료를 사용자 정의합니다.
rateLimit { enabled?: boolean; timeWindow?: number; maxRequests?: number; }
속도 제한을 사용자 정의합니다.
schema InferOptionSchema<ReturnType<typeof apiKeySchema>>
API 키 플러그인의 사용자 정의 스키마입니다.
disableSessionForAPIKeys boolean
API 키는 유효한 세션을 나타낼 수 있으므로 요청 헤더에서 유효한 API 키를 찾으면 자동으로 사용자에 대한 모의 세션을 생성합니다.
permissions { defaultPermissions?: Statements | ((userId: string, ctx: GenericEndpointContext) => Statements | Promise<Statements>) }
API 키의 권한입니다.
권한에 대한 자세한 내용은 여기를 참조하세요.
disableKeyHashing boolean
API 키의 해싱을 비활성화합니다.
⚠️ 보안 경고: 해싱을 비활성화하지 않는 것을 강력히 권장합니다. API 키를 평문으로 저장하면 데이터베이스 침해에 취약해져 모든 사용자의 API 키가 노출될 수 있습니다.
권한
API 키는 권한을 가질 수 있어 세밀한 수준에서 접근을 제어할 수 있습니다. 권한은 리소스 유형에 대한 허용된 작업 배열의 레코드로 구조화됩니다.
기본 권한 설정하기
새로 생성된 모든 API 키에 적용될 기본 권한을 구성할 수 있습니다:
export const auth = betterAuth({
plugins: [
apiKey({
permissions: {
defaultPermissions: {
files: ["read"],
users: ["read"],
},
},
}),
],
});권한을 동적으로 반환하는 함수를 제공할 수도 있습니다:
export const auth = betterAuth({
plugins: [
apiKey({
permissions: {
defaultPermissions: async (userId, ctx) => {
// 사용자 역할 또는 기타 데이터를 가져와 권한 결정
return {
files: ["read"],
users: ["read"],
};
},
},
}),
],
});권한과 함께 API 키 생성하기
API 키를 생성할 때 사용자 정의 권한을 지정할 수 있습니다:
const apiKey = await auth.api.createApiKey({
body: {
name: "My API Key",
permissions: {
files: ["read", "write"],
users: ["read"],
},
userId: "userId",
},
});필수 권한과 함께 API 키 검증하기
API 키를 검증할 때 필수 권한이 있는지 확인할 수 있습니다:
const result = await auth.api.verifyApiKey({
body: {
key: "your_api_key_here",
permissions: {
files: ["read"],
},
},
});
if (result.valid) {
// API 키가 유효하고 필수 권한이 있습니다
} else {
// API 키가 유효하지 않거나 필수 권한이 없습니다
}API 키 권한 업데이트하기
기존 API 키의 권한을 업데이트할 수 있습니다:
const apiKey = await auth.api.updateApiKey({
body: {
keyId: existingApiKeyId,
permissions: {
files: ["read", "write", "delete"],
users: ["read", "write"],
},
},
headers: user_headers,
});권한 구조
권한은 리소스 기반 구조를 따릅니다:
type Permissions = {
[resourceType: string]: string[];
};
// 예시:
const permissions = {
files: ["read", "write", "delete"],
users: ["read"],
projects: ["read", "write"],
};API 키를 검증할 때 검증이 성공하려면 필수 권한이 모두 API 키의 권한에 있어야 합니다.
스키마
테이블: apiKey
| Field Name | Type | Key | Description |
|---|---|---|---|
| id | string | API 키의 ID입니다. | |
| name | string | API 키의 이름입니다. | |
| start | string | API 키의 시작 문자입니다. 사용자가 쉽게 식별할 수 있도록 UI에 API 키의 처음 몇 문자를 표시하는 데 유용합니다. | |
| prefix | string | API 키 접두사입니다. 평문으로 저장됩니다. | |
| key | string | - | 해시된 API 키 자체입니다. |
| userId | string | API 키와 연결된 사용자의 ID입니다. | |
| refillInterval | number | 키를 재충전할 간격(밀리초)입니다. | |
| refillAmount | number | 키의 남은 횟수를 재충전할 양입니다. | |
| lastRefillAt | Date | 키가 마지막으로 재충전된 날짜 및 시간입니다. | |
| enabled | boolean | - | API 키가 활성화되어 있는지 여부입니다. |
| rateLimitEnabled | boolean | - | API 키에 속도 제한이 활성화되어 있는지 여부입니다. |
| rateLimitTimeWindow | number | 속도 제한의 시간 윈도우(밀리초)입니다. | |
| rateLimitMax | number | `rateLimitTimeWindow` 내에 허용되는 최대 요청 수입니다. | |
| requestCount | number | - | 속도 제한 시간 윈도우 내에 수행된 요청 수입니다. |
| remaining | number | 남은 요청 수입니다. | |
| lastRequest | Date | 키에 대한 마지막 요청의 날짜 및 시간입니다. | |
| expiresAt | Date | 키가 만료되는 날짜 및 시간입니다. | |
| createdAt | Date | - | API 키가 생성된 날짜 및 시간입니다. |
| updatedAt | Date | - | API 키가 업데이트된 날짜 및 시간입니다. |
| permissions | string | 키의 권한입니다. | |
| metadata | Object | 키와 함께 저장하려는 추가 메타데이터입니다. |