API-nøglen i headeren eller i URL'en (api_key)

Vælg mellem X-Api-Key-headeren og ?api_key= i URL'en, og send nøglen korrekt fra curl, Python, Node og PHP.

4 min Niveau: Begynder ✓ Kode testet

Hvert kald til https://api.danadresse.dk skal have en API-nøgle. Du kan sende den på to måder: i headeren X-Api-Key eller som query-parameteren api_key i URL'en. Begge virker på alle endpoints, både de DAWA-kompatible stier og /api/v1.

Brug headeren, når du kan. Denne guide forklarer hvorfor, og hvornår URL-varianten er det rigtige valg.

Sådan læser API'et nøglen

Serveren kigger først efter headeren X-Api-Key. Kun hvis den mangler eller er tom, læses api_key fra URL'en. Det har to konsekvenser:

  • Sender du begge, vinder headeren. En forkert nøgle i headeren giver 401 invalid_api_key, selv om URL'en har den rigtige.
  • En tom header (fx X-Api-Key: fordi miljøvariablen ikke er sat) tæller som manglende, og så bruges api_key fra URL'en, hvis den findes. Ellers får du 401 missing_api_key.

Header-navnet er ikke følsomt for store og små bogstaver, så x-api-key og X-API-KEY virker også. Mellemrum før og efter nøglen i headeren fjernes.

Header: anbefalet fra servere og scripts

Med curl:

Shell#header-curl
curl -s "https://api.danadresse.dk/postnumre/8000" \
  -H "X-Api-Key: $DANADRESSE_API_KEY"

Med Python og requests:

Python#header-python
import os
import requests

r = requests.get(
    "https://api.danadresse.dk/postnumre/8000",
    headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]},
    timeout=10,
)
r.raise_for_status()
print(r.json()["navn"])

Med Node 18 eller nyere:

JavaScript#header-node
const res = await fetch("https://api.danadresse.dk/postnumre/8000", {
  headers: { "X-Api-Key": process.env.DANADRESSE_API_KEY },
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
const postnummer = await res.json();
console.log(postnummer.navn);

Med PHP og curl-udvidelsen:

PHP#header-php
<?php
$ch = curl_init("https://api.danadresse.dk/postnumre/8000");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => ["X-Api-Key: " . getenv("DANADRESSE_API_KEY")],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
    fwrite(STDERR, "HTTP $status: $body\n");
    exit(1);
}
echo json_decode($body, true)["navn"], "\n";

Query-parameter: når du ikke kan sætte en header

?api_key= findes, fordi nogle steder kun lader dig angive en URL:

  • et <script src="…">-tag, fx DAWA's gamle widget: https://api.danadresse.dk/js/autocomplete/dawa-autocomplete2.min.js?key=dawa_live_… (widgetten sender derefter nøglen som api_key på hvert kald)
  • regneark og værktøjer, der kun kan hente en URL, fx IMPORTDATA i Google Sheets
  • en hurtig test i browserens adresselinje
Shell#query-curl
curl -s "https://api.danadresse.dk/postnumre/8000?api_key=$DANADRESSE_API_KEY"

I browseren er der en ekstra forskel. En brugerdefineret header som X-Api-Key får browseren til at sende et CORS-preflight (OPTIONS) før det rigtige kald. API'et svarer ja og beder browseren huske svaret i op til et døgn (nogle browsere husker det kortere). Preflightet tæller ikke som et API-kald. Med api_key i URL'en er kaldet en "simple request" uden preflight. Begge dele virker, så vælg ud fra, hvad dit bibliotek gør nemmest.

Hvorfor headeren er det sikre valg

En URL bliver kopieret mange steder, som du ikke styrer:

  • access-logs i proxyer, load balancers og firewalls mellem dig og API'et
  • fejlrapporteringsværktøjer, der gemmer den fulde request-URL
  • shell-historik, CI-logs og skærmbilleder af browserens netværksfane
  • HAR-filer, som du sender til support

Vores egne applikationslogs maskerer værdien af api_key= (den bliver til api_key=***, og det samme gælder X-Api-Key-headeren). Du kan ikke regne med, at alle andre led på vejen gør det samme.

En header havner sjældnere i logs. Den er ikke hemmelig over for den, der kører koden. I en browser kan enhver besøgende se nøglen i netværksfanen, uanset om den ligger i header eller URL. Til kode, der kører hos dine besøgende, skal du derfor bruge en domænelåst browsernøgle, se Browsernøgler og tilladte domæner.

Hvilken metode skal jeg bruge?

SituationMetodeNøgletype
Backend, cron-job, ETL, CIX-Api-Key-headerServernøgle fra miljøvariabel
fetch i browseren, React, VueHeader eller api_keyDomænelåst browsernøgle
<script src> til en widget?key= / api_key i URL'enDomænelåst browsernøgle
Google Sheets IMPORTDATA, simple værktøjerapi_key i URL'enSeparat nøgle, som du kan rotere
Udvikling og automatiske testsHeaderTestnøgle (dawa_test_…)

Masker nøglen i dine egne logs

Logger din applikation udgående URL'er, så fjern nøglen, før linjen skrives. Et logging-filter i Python, der gør det samme som vores:

Python#redact-filter
import logging
import re

_SECRET = re.compile(r"(?i)((?:api_key|apikey)=|x-api-key\s*[:=]\s*)([^&\s\"']+)")


class RedactApiKey(logging.Filter):
    """Erstat API-nøgler i logbeskeder med ***."""

    def filter(self, record: logging.LogRecord) -> bool:
        record.msg = _SECRET.sub(r"\1***", str(record.msg))
        if record.args:
            record.args = tuple(
                _SECRET.sub(r"\1***", a) if isinstance(a, str) else a
                for a in record.args
            )
        return True


handler = logging.StreamHandler()
handler.addFilter(RedactApiKey())
logging.basicConfig(level=logging.INFO, handlers=[handler])
logging.getLogger("demo").info("GET https://api.danadresse.dk/postnumre?api_key=dawa_live_hemmelig")

Filteret skriver api_key=*** i stedet for nøglen.

Hvis nøglen er lækket

Har en nøgle stået i en URL, der er endt i en offentlig log eller et repository, så opret en ny nøgle under Nøgler, skift den ind i din konfiguration og slet den gamle. En live-nøgle, der bruges fra mange forskellige IP-adresser samme dag, bliver markeret som lækket, og du får en mail. Se Fejl 403 for, hvad der sker, hvis den ikke bliver skiftet.

Næste skridt

Relaterede guides

Markdown-kilde Fejl i guiden? Skriv til os API-reference (Swagger)

Prøv det med en gratis nøgle

2 000 kald/måned på gratisplanen. Intet kreditkort.

Opret konto →