API 키는 서비스의 현관 열쇠와 같습니다. 이를 통해 사용자가 보안을 유지하면서 들어갈 수 있습니다. 이 블로그에서는 빠른 서버리스 데이터 스토리지를 위한 Upstash Redis와 엣지에서 요청을 처리하는 Cloudflare Workers를 사용하여 간단하고 안전한 API 키 생성기를 구축하는 과정을 안내하겠습니다. 새로운 서비스를 설정하든 기존 앱에 키를 추가하든 모든 것이 원활하고 효율적으로 실행되도록 API 키를 생성, 저장 및 검증하는 방법을 배우게 됩니다.
API 키란 무엇인가요?
API 키는 API에 액세스하려는 사용자나 애플리케이션을 식별하고 인증하는 고유 코드입니다. 개인 패스처럼 생각하십시오. 누군가 귀하의 서비스를 사용하려면 허용되었음을 증명하기 위해 이 "키"를 제시해야 합니다. API 키는 리소스에 액세스할 수 있는 사람을 제어하는 데 도움이 되며 사용량을 추적하고 제한을 적용하거나 무단 액세스를 방지하는 데 자주 사용됩니다. 이는 API 액세스를 관리하고 데이터를 안전하게 유지하는 간단한 방법입니다.
우리가 구축할 것
이 가이드에서는 두 가지 핵심 기능을 제공하는 API 키 생성기를 만듭니다:
- 맞춤 설정으로 새 API 키 생성
- 메타데이터를 검색하는 동안 API 키 유효성 검사
주요 기능은 다음과 같습니다:
- 맞춤설정 가능한 키 접두어
- 만료일
- 속도 제한
- 메타데이터 저장
- 소유자 식별
API 키 시스템을 시각화해 보겠습니다
이 다이어그램은 API 키 생성 및 검증을 위한 클라이언트, Cloudflare Worker 및 Upstash Redis 간의 상호 작용을 보여줍니다. 이러한 개요를 염두에 두고 시스템 구축을 시작하겠습니다.

전제조건
따라가려면 다음이 필요합니다:
- Cloudflare 작업자 계정
- 업스태시 계정
- 로컬 컴퓨터에 설치된 Node.js
프로젝트 구조
우리 프로젝트는 다음과 같은 구조를 갖습니다:
folder-name/
├── src/
│ ├── config/
│ │ ├── generateApiKey.ts
│ │ └── schema-validation.ts
│ ├── lib/
│ │ └── ratelimit.ts
│ ├── routes/
│ │ ├── create.ts
│ │ └── verify.ts
│ ├── types/
│ │ └── api.ts
│ └── index.ts
├── package.json
└── wrangler.toml
1단계:프로젝트 설정
프로젝트를 설정하고 필요한 종속성을 설치하는 것부터 시작해 보겠습니다.
새 프로젝트 디렉토리 생성
터미널을 열고 다음 명령을 실행하세요:
mkdir keyflow
cd keyflow
npm init -y 종속성 설치
우리 프로젝트에는 몇 가지 패키지가 필요합니다:
npm install hono @upstash/redis @upstash/ratelimit @hono/zod-validator zod wrangler
@upstash/redis :서버리스 환경을 위한 Upstash Redis 클라이언트@upstash/ratelimit :Upstash Redis@hono/zod-validator용 속도 제한 라이브러리 :Honozod용 검증 미들웨어 요청 :TypeScript 우선 스키마 검증 라이브러리wrangler :작업자 개발 및 배포를 위한 Cloudflare의 CLI
Upstash Redis 설정
- Upstash 계정에 로그인하고 새로운 Redis 데이터베이스를 생성하세요

- 생성되면 "REST API" 섹션으로 이동하세요.

UPSTASH_REDIS_REST_URL을 복사하세요. 및UPSTASH_REDIS_REST_TOKEN.env에서 섹션
Cloudflare 작업자 구성
wrangler.toml 만들기 다음 내용으로 프로젝트 루트에 파일을 저장하세요:
name = "keyflow"
main = "src/index.ts"
compatibility_date = "2023-05-18"
[vars]
UPSTASH_REDIS_REST_URL = "your-redis-url"
UPSTASH_REDIS_REST_TOKEN = "your-redis-token"
"your-redis-url" 바꾸기 및 "your-redis-token" Upstash에서 복사한 값으로 변경하세요.
2단계:API 유형 정의
API 요청 및 응답을 위한 TypeScript 인터페이스를 정의하는 것부터 시작해 보겠습니다. 이러한 유형은 애플리케이션 전체에서 유형 안전성을 유지하는 데 도움이 됩니다. 새 파일 src/types/api.ts 만들기 :
export type CreateKeyRequest = {
apiId: string;
prefix?: string;
byteLength?: number;
ownerId?: string;
name: string;
meta?: Record<string, unknown>;
expires?: number;
ratelimit?: {
type: "fast" | "consistent";
limit: number;
refillRate: number;
refillInterval: number;
};
};
export type CreateKeyResponse = {
key: string;
keyId: string;
};
export type VerifyKeyRequest = {
key: string;
};
export type VerifyKeyResponse = {
valid: boolean;
ownerId?: string;
meta?: Record<string, unknown>;
expires?: number;
ratelimit?: {
limit: number;
remaining: number;
reset: number;
};
};
export type Env = {
UPSTASH_REDIS_REST_URL: string;
UPSTASH_REDIS_REST_TOKEN: string;
};
3단계:API 키 생성 구현
이제 API 키를 생성하는 유틸리티 함수를 만들어 보겠습니다. 새 파일 src/config/generateApiKey.ts 만들기 :
export function generateApiKey(
prefix: string | undefined,
byteLength: number,
): string {
const randomBytes = crypto.getRandomValues(new Uint8Array(byteLength));
const key = btoa(String.fromCharCode(...new Uint8Array(randomBytes)))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
return prefix ? `${prefix}_${key}` : key;
}
이 함수는 암호화된 무작위 바이트를 사용하여 무작위 API 키를 생성하고 이를 base64로 인코딩하여 URL로부터 안전하게 만듭니다.
4단계:속도 제한 구현
src/lib/ratelimit.ts 파일 만들기 :
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis/cloudflare";
import type { Context, Next } from "hono";
import { env } from "hono/adapter";
import type { Env } from "../types/api";
// Middleware for rate limiting
export async function rateLimitMiddleware(c: Context, next: Next) {
const { UPSTASH_REDIS_REST_TOKEN, UPSTASH_REDIS_REST_URL } = env<Env>(c);
const redis = new Redis({
url: UPSTASH_REDIS_REST_URL,
token: UPSTASH_REDIS_REST_TOKEN,
});
const ratelimit = new Ratelimit({
redis: redis,
limiter: Ratelimit.slidingWindow(5, "30 s"),
});
const ip = c.req.header("CF-Connecting-IP") || "127.0.0.1";
const { success, limit, remaining, reset } = await ratelimit.limit(ip);
if (!success) {
return c.json({ error: "Rate limit exceeded" }, 429);
}
c.header("X-RateLimit-Limit", limit.toString());
c.header("X-RateLimit-Remaining", remaining.toString());
c.header("X-RateLimit-Reset", reset.toString());
await next();
} 5단계:API 경로 생성
기본 애플리케이션 파일을 설정하고 API 경로를 생성해 보겠습니다. 이 파일은 두 가지 주요 경로(/keys/create)로 Hono 애플리케이션을 설정합니다. 새로운 API 키 및 /keys/verify 생성용 세 개의 별도 파일로 기존 키를 검증합니다.
1. API 키 경로 생성 구현
src/routes/create.ts 파일 만들기 :
import { zValidator } from "@hono/zod-validator"
import { Redis } from "@upstash/redis/cloudflare"
import { Hono } from "hono"
import { generateApiKey } from "../config/generateApiKey"
import { createApiKeySchema } from "../config/schema-validation"
import type { CreateKeyRequest, CreateKeyResponse, Env } from "../types/api"
const create = new Hono<{
Bindings: Env
}>()
create.post(
"/create",
zValidator("json", createApiKeySchema, (result, c) => {
if (!result.success) {
return c.text("Invalid!", 400)
}
}),
async (c) => {
// Initialize Redis client
const { UPSTASH_REDIS_REST_TOKEN, UPSTASH_REDIS_REST_URL } = c.env
const redis = new Redis({
url: UPSTASH_REDIS_REST_URL,
token: UPSTASH_REDIS_REST_TOKEN,
})
const body = await c.req.json<CreateKeyRequest>()
// Generate unique identifier and API key
const keyId = crypto.randomUUID()
const key = generateApiKey(body.prefix, body.byteLength || 16)
const keyData = {
...body,
key,
keyId,
createdAt: Date.now(),
}
const encodedKey = encodeURIComponent(key)
try {
// Store key data and lookup reference in Redis
await redis.set(`key:${keyId}`, JSON.stringify(keyData))
await redis.set(`lookup:${encodedKey}`, keyId)
return c.json<CreateKeyResponse>({ key, keyId })
} catch (error) {
console.error("Error in /keys/create:", error)
return c.json({ error: "Internal Server Error" }, 500)
}
}
)
export default create 2. API 키 경로 확인 구현
src/routes/verify.ts 파일 만들기 :
import { zValidator } from "@hono/zod-validator";
import { Redis } from "@upstash/redis/cloudflare";
import { Hono } from "hono";
import { verifyApiKeySchema } from "../config/schema-validation";
import type {
CreateKeyRequest,
Env,
VerifyKeyRequest,
VerifyKeyResponse,
} from "../types/api";
// Initialize Hono app with environment bindings
const verify = new Hono<{ Bindings: Env }>();
// Define POST route for verifying an API key
verify.post(
"/verify",
// Validate request body against schema
zValidator("json", verifyApiKeySchema, (result, c) => {
if (!result.success) {
return c.text("Invalid!", 400); // Return 400 if validation fails
}
}),
async (c) => {
// Set up Redis with environment variables
const { UPSTASH_REDIS_REST_TOKEN, UPSTASH_REDIS_REST_URL } = c.env;
const redis = new Redis({
url: UPSTASH_REDIS_REST_URL,
token: UPSTASH_REDIS_REST_TOKEN,
});
const body = await c.req.json<VerifyKeyRequest>();
if (!body.key) {
return c.json({ error: "key is required" }, 400); // Require key in the request body
}
const encodedKey = encodeURIComponent(body.key);
const keyId = await redis.get<string>(`lookup:${encodedKey}`); // Retrieve key ID using encoded key
if (!keyId) {
return c.json<VerifyKeyResponse>({ valid: false }); // Key not found
}
const keyDataString = await redis.get<string>(`key:${keyId}`); // Retrieve key data by key ID
if (!keyDataString || typeof keyDataString !== "string") {
return c.json<VerifyKeyResponse>({ valid: false }); // Key data missing or invalid
}
let keyData: CreateKeyRequest & {
key: string;
keyId: string;
createdAt: number;
};
try {
keyData = JSON.parse(keyDataString); // Parse key data
} catch (parseError) {
// Handle parse error by deleting invalid data
console.error("Key data parse error:", parseError);
await Promise.all([
redis.del(`key:${keyId}`),
redis.del(`lookup:${encodedKey}`),
]);
return c.json(
{
error: "Invalid key data in storage",
details: parseError instanceof Error ? parseError.message : "Unknown parse error",
valid: false,
},
500,
);
}
// Check if key has expired
if (keyData.expires && keyData.expires < Date.now()) {
await Promise.all([
redis.del(`key:${keyId}`),
redis.del(`lookup:${encodedKey}`),
]);
return c.json<VerifyKeyResponse>({ valid: false });
}
// Formulate response with validation status and metadata
const response: VerifyKeyResponse = {
valid: true,
ownerId: keyData.ownerId,
meta: keyData.meta,
expires: keyData.expires,
};
if (keyData.ratelimit) {
response.ratelimit = {
limit: keyData.ratelimit.limit,
remaining: keyData.ratelimit.limit,
reset: Date.now() + keyData.ratelimit.refillInterval,
};
}
return c.json(response); // Return verification response
},
);
export default verify;
3. 기본 파일 index.ts 구현
메인 파일 src/index.ts 구현 create.ts 가져오기 , verify.ts 및 rateLimitMiddleWare
import { Hono } from "hono";
import { rateLimitMiddleware } from "./lib/ratelimit";
import create from "./routes/create";
import verify from "./routes/verify";
import type { Env } from "./types/api";
const app = new Hono<{
Bindings: Env;
}>().basePath("/keys");
app.use("*", rateLimitMiddleware);
// add the create file route and verify file route
app.route("/", create);
app.route("/", verify);
export default app;
6단계:배포
Cloudflare Workers에 Keyflow 애플리케이션을 배포하세요:
-
랭글러 설치:
npm install -g wrangler -
Cloudflare로 인증:
wrangler login -
작업자 배포:
wrangler deploy
7단계:배포
이제 애플리케이션이 준비되었으므로 Cloudflare Workers에 배포해 보겠습니다.
-
Wrangler CLI가 설치되어 있는지 확인하세요:
npm install -g wrangler -
Cloudflare 계정으로 인증하세요:
wrangler login -
작업자 배포:
wrangler deploy
8단계:API 테스트
새로 배포된 API를 테스트해 보겠습니다.
새 API 키 생성
curl -X POST https://keyflow.<your-subdomain>.workers.dev/keys/create \
-H "Content-Type: application/json" \
-d '{
"apiId": "my-api",
"prefix": "prod",
"name": "Production API Key",
"expires": 1735689600000,
"meta": {
"environment": "production",
"team": "backend"
}
}'
API 키 확인
curl -X POST https://keyflow.<your-subdomain>.workers.dev/keys/verify \
-H "Content-Type: application/json" \
-d '{
"key": "prod_AbC123XyZ..."
}'
<your-subdomain> 바꾸기 Cloudflare Workers 하위 도메인 및 prod_AbC123XyZ... 생성 엔드포인트에서 생성된 실제 키를 사용합니다.
결론
API 키 생성기를 만드는 것은 애플리케이션의 API를 보호하고 서비스에 액세스할 수 있는 사람을 관리하는 핵심 단계입니다. API 키를 생성, 검증, 관리할 수 있는 시스템을 구축함으로써 데이터를 안전하게 정리하는 데 도움이 되는 강력한 액세스 제어 계층을 추가할 수 있습니다.
다음은 견고한 API 키 생성기에 들어가는 내용에 대한 간략한 요약입니다:
- 보안 키 생성 :맞춤 접두사 또는 길이 설정과 같은 옵션이 포함된 고유하고 안전한 키는 각 키를 구별하고 추측하기 어렵게 만듭니다.
- 확인 및 만료 :확인 및 만료 날짜를 추가하면 각 키가 설정된 시간 동안만 유효한지 확인하여 필요에 따라 액세스를 쉽게 제어하고 제한할 수 있습니다.
- 메타데이터 및 속도 제한 :각 키와 함께 추가 정보를 저장하고 속도 제한을 설정하면 키 사용을 모니터링하고 활동을 추적하며 API 남용을 방지할 수 있습니다.
Upstash Redis 및 Cloudflare Workers와 같은 도구를 사용하면 확장성이 뛰어나고 효율적으로 작동하는 서버리스 및 전 세계적으로 분산된 키 관리 시스템을 쉽게 구축할 수 있습니다.
이러한 기반을 통해 API에 대한 액세스를 안전하고 관리 가능하게 유지함으로써 리소스가 보호되고 쉽게 모니터링할 수 있다는 확신을 갖게 됩니다.