Foto av Sasun Bughdaryan via Unsplash
API-nycklar: Skapa, hantera och skydda dina API-credentials
Lär dig vad en API-nyckel är, hur du genererar säkra nycklar och vilka best practices som skyddar ditt API mot missbruk. Komplett guide med kodexempel.
Vad är en API-nyckel?
En API-nyckel är en unik sträng som identifierar en klient som anropar ett API. Den fungerar som ett enkelt autentiseringsmedel: klienten skickar nyckeln med varje request, och servern kontrollerar att nyckeln är giltig innan den tillåter åtkomst.
Till skillnad från OAuth 2.0, som hanterar delegerad behörighet med tokens och scopes, är API-nycklar en enklare mekanism. De passar bäst för server-till-server-kommunikation, publika API:er med rate limiting och interna mikrotjänster där fullständig OAuth-flöden vore överflödiga.
Vanliga användningsområden inkluderar kartverktyg (Google Maps), betalningslösningar (Stripe), väderdata och CMS-API:er. Om du vill förstå skillnaden mot mer avancerad autentisering, se vår guide om OAuth 2.0-implementation.
// API-nyckel skickas vanligtvis i en header
curl -X GET https://api.example.com/v1/products \
-H "X-API-Key: sk_live_a1b2c3d4e5f6g7h8i9j0"
// Eller som query parameter (mindre säkert)
curl "https://api.example.com/v1/products?api_key=sk_live_a1b2c3d4e5f6g7h8i9j0"
// Header-metoden är att föredra:
// - Nyckeln hamnar inte i serverloggar
// - Syns inte i webbläsarens historik
// - Delas inte vid referer-headersGenerera säkra API-nycklar
En API-nyckel ska vara tillräckligt lång och slumpmässig för att vara omöjlig att gissa. Minst 32 bytes (256 bitar) entropi ger ett robust skydd. Använd kryptografiskt säkra slumptalsgeneratorer, aldrig Math.random() eller liknande.
Bra praxis är att lägga till ett prefix som indikerar nyckelns typ och miljö. Stripe använder exempelvis sk_live_ för produktionsnycklar och sk_test_ för testmiljön. Prefixet gör det enkelt att identifiera en nyckel om den dyker upp i loggar eller kod, utan att exponera själva hemligheten.
import crypto from "crypto";
// Generera kryptografiskt säker API-nyckel
function generateApiKey(prefix: string = "sk"): string {
const randomBytes = crypto.randomBytes(32);
const key = randomBytes.toString("base64url");
return `${prefix}_${key}`;
}
// Exempel:
// sk_YjQ1ZmE3MDktNzRjYi00MGNmLTk2ZjItZTg3N2QxYjA2MmVh
// Lagra ALLTID en hashad version i databasen
async function storeApiKey(userId: string): Promise<string> {
const plainKey = generateApiKey("sk_live");
// Hasha nyckeln med SHA-256 innan lagring
const hashedKey = crypto
.createHash("sha256")
.update(plainKey)
.digest("hex");
await db.apiKeys.create({
data: {
userId,
keyHash: hashedKey,
prefix: plainKey.slice(0, 8), // Spara prefix för identifiering
createdAt: new Date(),
},
});
// Returnera plain key BARA vid skapande
return plainKey;
}Validering och middleware
API-nyckelvalidering sker i en middleware som körs före varje skyddad route. Middlewaren extraherar nyckeln från headern, hashar den och söker i databasen. Att hasha innan lookup innebär att även om databasen läcker exponeras aldrig faktiska nycklar.
Implementera cachning av nyckeluppslagningar för att undvika en databasfråga per request. Redis eller en in-memory LRU-cache med kort TTL (30-60 sekunder) minskar latensen avsevärt. Invalidering sker när en nyckel återkallas eller uppdateras.
import crypto from "crypto";
interface ApiKeyRecord {
userId: string;
keyHash: string;
scopes: string[];
rateLimit: number;
isActive: boolean;
}
// LRU-cache för snabb validering
const keyCache = new Map<string, { record: ApiKeyRecord; expiresAt: number }>();
const CACHE_TTL = 30_000; // 30 sekunder
async function validateApiKey(key: string): Promise<ApiKeyRecord | null> {
const hash = crypto.createHash("sha256").update(key).digest("hex");
// Kolla cache först
const cached = keyCache.get(hash);
if (cached && cached.expiresAt > Date.now()) {
return cached.record;
}
// Databas-lookup
const record = await db.apiKeys.findUnique({
where: { keyHash: hash, isActive: true },
});
if (record) {
keyCache.set(hash, {
record,
expiresAt: Date.now() + CACHE_TTL,
});
}
return record;
}
// Express middleware
export function requireApiKey(requiredScopes?: string[]) {
return async (req, res, next) => {
const key = req.headers["x-api-key"];
if (!key || typeof key !== "string") {
return res.status(401).json({
error: "api_key_required",
message: "Ange en giltig API-nyckel i X-API-Key headern",
});
}
const record = await validateApiKey(key);
if (!record) {
return res.status(403).json({
error: "invalid_api_key",
message: "API-nyckeln är ogiltig eller inaktiverad",
});
}
// Kontrollera scopes
if (requiredScopes?.length) {
const hasScope = requiredScopes.every((s) =>
record.scopes.includes(s)
);
if (!hasScope) {
return res.status(403).json({
error: "insufficient_scope",
message: "API-nyckeln saknar behörighet",
});
}
}
req.apiKeyRecord = record;
next();
};
}Rotation och livscykelhantering
API-nycklar bör roteras regelbundet, precis som lösenord. Implementera stöd för att en användare kan ha flera aktiva nycklar samtidigt. Det möjliggör sömlös rotation: skapa en ny nyckel, uppdatera klienten, och revokera den gamla utan avbrott.
Sätt utgångsdatum på nycklar och skicka varningar innan de löper ut. Logga alla nyckelrelaterade händelser (skapande, användning, revokering) för spårbarhet och säkerhetsaudit.
// Nyckelrotation med överlappningsperiod
async function rotateApiKey(userId: string, oldKeyPrefix: string) {
// 1. Skapa ny nyckel
const newKey = await storeApiKey(userId);
// 2. Markera gamla nyckeln som "deprecated" (inte borttagen)
await db.apiKeys.updateMany({
where: {
userId,
prefix: oldKeyPrefix,
isActive: true,
},
data: {
deprecatedAt: new Date(),
// Ge klienten 24h att byta
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
},
});
// 3. Logga rotationen
await db.auditLog.create({
data: {
userId,
action: "api_key_rotated",
metadata: { oldPrefix: oldKeyPrefix },
},
});
return newKey;
}
// Automatisk cleanup av utgångna nycklar (cron-jobb)
async function cleanupExpiredKeys() {
const expired = await db.apiKeys.updateMany({
where: {
expiresAt: { lt: new Date() },
isActive: true,
},
data: { isActive: false },
});
console.log(`Inaktiverade ${expired.count} utgångna API-nycklar`);
}Vanliga misstag och säkerhetsprinciper
Det vanligaste misstaget är att committa API-nycklar i versionskontroll. Även om du tar bort nyckeln i en senare commit finns den kvar i git-historiken. Använd environment variables och .env-filer (som aldrig committas) för att hantera nycklar.
Skicka aldrig API-nycklar som query parameters i produktionsmiljö. Query strings loggas av webbservrar, proxyservrar och CDN:er. Använd alltid headers. Begränsa varje nyckel till de scopes och IP-adresser som faktiskt behövs.
Implementera rate limiting per nyckel och övervaka ovanliga mönster. En nyckel som plötsligt skickar tio gånger fler requests än normalt kan vara komprometterad. Automatisera blockering vid misstänkt beteende.
För djupare skydd kan du kombinera API-nycklar med request-signering (HMAC). Klienten signerar varje request med en hemlig nyckel, och servern verifierar signaturen. Detta skyddar mot man-in-the-middle-attacker även om nyckeln exponeras. Läs mer om rate limiting och API-throttling i vår dedikerade guide.