API keys are the simplest form of authentication. Think of it like a gym membership card. You swipe it at the door. The gym does not care who you are — they just check if the card is valid. No username, no password. Just a single string.
Developer signs up on the API provider's website (e.g., OpenWeatherMap, Google Maps)
Provider generates a unique key — a long random string like "a1b2c3d4e5f6"
Developer sends this key with every API request
Server checks: is this key valid? Is it active? Is it within rate limits?
If valid — returns data. If not — returns 401 or 403.
There are three common places to send an API key. The API documentation tells you which one to use. You do not get to pick.
| Method | Example | When Used |
|---|---|---|
| Header | X-API-Key: abc123 | Most common. Preferred. Key is not visible in URL. |
| Query Parameter | ?api_key=abc123 | Simpler APIs. Key is in the URL — can leak in logs. |
| Request Body | { "apiKey": "abc123" } | Rare. Only some legacy APIs do this. |
Never send API keys as query parameters in production. They show up in browser history, server logs, and proxy logs. Headers are safer. If you see an API that only supports query param keys — that is a red flag about their security practices.
// Postman: Set API key in the Authorization tab
// Type: API Key
// Key: X-API-Key
// Value: {{apiKey}}
// Add to: Header
// OR set it manually in the Headers tab:
// Header: X-API-Key
// Value: {{apiKey}}
// Tests tab — verify responses
pm.test("Valid API key returns 200", function () {
pm.response.to.have.status(200);
});
pm.test("Response has data", function () {
const json = pm.response.json();
pm.expect(json).to.have.property("data");
});
// To test INVALID key:
// Change the value to "invalid-key-123" and run again
pm.test("Invalid API key returns 401", function () {
pm.response.to.have.status(401);
const json = pm.response.json();
pm.expect(json.error).to.include("unauthorized");
});
// To test MISSING key:
// Remove the header entirely
pm.test("Missing API key returns 401", function () {
pm.response.to.have.status(401);
});import io.restassured.RestAssured;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class ApiKeyAuthTest {
@BeforeClass
public void setup() {
RestAssured.baseURI = "https://api.example.com";
}
@Test
public void testValidApiKey() {
given()
.header("X-API-Key", "your-valid-api-key-here")
.when()
.get("/weather?city=Mumbai")
.then()
.statusCode(200)
.body("city", equalTo("Mumbai"))
.body("temperature", notNullValue());
}
@Test
public void testInvalidApiKey() {
given()
.header("X-API-Key", "invalid-garbage-key")
.when()
.get("/weather?city=Mumbai")
.then()
.statusCode(401)
.body("error", containsString("unauthorized"));
}
@Test
public void testMissingApiKey() {
given()
// No API key header at all
.when()
.get("/weather?city=Mumbai")
.then()
.statusCode(401);
}
@Test
public void testApiKeyAsQueryParam() {
given()
.queryParam("api_key", "your-valid-api-key-here")
.when()
.get("/weather?city=Mumbai")
.then()
.statusCode(200);
}
}Store API keys in environment variables or config files. In REST Assured, use System.getenv("API_KEY") instead of hardcoding. In Postman, use environment variables like {{apiKey}}. Never commit real keys to git.
Q: What is the difference between API key authentication and token-based authentication?
A: API key is a static string that does not change — it identifies the application, not the user. Token-based auth (like JWT) identifies a specific user, has an expiry time, and is generated after login. API keys are simpler but less secure — if leaked, they work until manually revoked. Tokens expire automatically. Most real apps use API keys for server-to-server calls and tokens for user-facing APIs.
Key Point: API keys are the simplest auth mechanism. They identify the app, not the user. Send them in headers, not query params. Always test missing, invalid, and expired key scenarios.