Guide
Legitimasjon og tokener
En legitimasjon identifiserer integrasjonen din inne i én kundes Visena-instans; et access token er det kortlevde beviset du sender med hvert kall. Denne siden er mekanikken for begge — opprettet på sekunder, tilbakekalt med ett kall, og hemmeligheten vises nøyaktig én gang.
Begreper forklarer hva en legitimasjon, et token og et scope er, og hvor de hører hjemme. Denne siden går ut fra at du har lest det og vil lage dem. Den dekker tre oppgaver som hører sammen, og er derfor lang med vilje:
- Håndtere API-legitimasjon — legitimasjons-API-et: opprette, liste, trekke tilbake, rotere.
- Opprette legitimasjon og token i grensesnittet — samme vei klikk for klikk, med hver skjerm vist.
- Hente et access token — token-forespørselen, scope-reglene, en cache å kopiere, og feilene.
Håndtere API-legitimasjon
En legitimasjon er et par: en clientId som navngir den og en clientSecret som beviser den. Alt under skjer inne i én kundes instans, mot instansens egen URL — under /{instanceName}/auth/api/v1/. Legitimasjons-endepunktene bærer et {locale}-segment etter versjonen — /acme/auth/api/v1/en/credentials — mens token-endepunktet ikke gjør det.
Legitimasjons-API-et autentiserer med en Visena-brukersesjon (X-ACCESS-TOKEN-informasjonskapselen til en innlogget bruker) — ikke med et bearer-token. Det er et bevisst valg: en maskinlegitimasjon kan ikke opprette flere legitimasjoner.
Hvem oppretter den
Legitimasjon opprettes inne i kundens instans, autentisert med en Visena-brukerinnlogging — så i de fleste integrasjonene er det kundens Visena-administrator som oppretter legitimasjonen og gir deg paret gjennom en sikker kanal. Forespørslene under dokumenterer hva som skjer i det steget, uansett om det er du eller kunden som utfører det.
Opprette en legitimasjon
To felter, begge påkrevde:
| Felt | Verdi |
|---|---|
label | En etikett som sier hva legitimasjonen er til. Kall den opp etter systemet som skal holde den — det takker du deg selv for når du senere skal rotere eller trekke tilbake. |
accessLevel | READ_ONLY eller READ_WRITE — taket på alt legitimasjonen noen gang kan utstede, og det kan ikke endres etterpå. Utelater du feltet, svarer endepunktet 400: nivået er ikke noe plattformen gjetter. To tak, ikke ett forklarer forholdet til scopet du ber om per token. |
En legitimasjon opprettet gjennom dette API-et handler alltid som brukeren som oppretter den. Skal den handle som en annen, opprettes den i grensesnittet i stedet — se legitimasjon på vegne av en annen.
curl -X POST https://api.visena.example/acme/auth/api/v1/en/credentials \
--cookie "X-ACCESS-TOKEN=<your Visena login session>" \
-H "Content-Type: application/json" \
-d '{ "label": "erp-sync-prod", "accessLevel": "READ_WRITE" }'
{
"id": "aX8k2m",
"label": "erp-sync-prod",
"clientId": "acme-partner-3f9a",
"accessLevel": "READ_WRITE",
"clientSecret": "vco_9tK2…",
"createdAt": "2026-08-21T09:14:03.482+02:00"
}
clientSecret vises nøyaktig én gang — i dette svaret. Visena lagrer bare en enveis hash og kan aldri vise den igjen. Legg den rett i hemmelighetshåndteringen din. Blir den mistet eller lekket, finnes det ingen «vis igjen» og ingen nullstilling: opprett en ny legitimasjon og trekk tilbake den gamle.
Liste legitimasjonene dine
Listingen returnerer bare metadata — aldri en hemmelighet. Bruk den til å se hva som finnes og til å finne den id-en du trenger for å trekke tilbake.
curl https://api.visena.example/acme/auth/api/v1/en/credentials \
--cookie "X-ACCESS-TOKEN=<session>"
# 200 OK
[
{ "id": "aX8k2m", "label": "erp-sync-prod", "clientId": "acme-partner-3f9a",
"accessLevel": "READ_WRITE", "createdAt": "2026-08-21T09:14:03.482+02:00" }
]
Trekke tilbake en legitimasjon
Tilbakekalling er en DELETE på legitimasjonens id (den maskerte id-en fra opprett/list — ikke clientId).
Tilbakekalling er umiddelbar og permanent. Legitimasjonen kan ikke lenger utstede tokener, og tokener den allerede har utstedt slutter å virke innen omtrent ett minutt. Det finnes ingen angre og ingen ny utstedelse av samme par: alt som fortsatt bruker den, trenger en ny legitimasjon fra en ny opprettelse. Raden slettes ikke — den blir stående i oversikten med statusen Tilbakekalt, med tidspunktet og hvem som gjorde det.
curl -X DELETE https://api.visena.example/acme/auth/api/v1/en/credentials/aX8k2m \
--cookie "X-ACCESS-TOKEN=<session>"
# 204 No Content — done
Rotering, i tre trekk
- Opprett erstatningen — samme navnekonvensjon, for eksempel
erp-sync-prod-2026q4. Begge legitimasjonene virker gjennom byttet; det finnes ikke noe nedetidsvindu. - Rull ut det nye paret — oppdater hemmelighetslageret, rull ut på tjenestene dine, bekreft at token-utstedelse virker med den nye
clientId-en. - Trekk tilbake den gamle legitimasjonen —
DELETE …/credentials/{id}. Alt som fortsatt bruker den, feiler fort og tydelig, som er nøyaktig det du vil.
Roter etter en plan som passer sikkerhetspolicyen din, og alltid når en person med tilgang til hemmeligheten går ut av prosjektet.
Legitimasjon på vegne av en annen
Når integrasjonen din må handle som en bestemt bruker — for eksempel arkivere dokumenter i en saksbehandlers navn — ber du kundens administrator om en legitimasjon på vegne av den brukeren. Slike utstedes gjennom Visenas administrasjonsverktøy, ikke gjennom selvbetjenings-API-et over. De oppfører seg likt, med to forskjeller:
- Token-forespørsler må bruke
act-as-user:-scopene —act-as-user:read act-as-user:writefor en legitimasjon opprettet som Les og skriv,act-as-user:readalene for en opprettet som Bare lesing. Å be om renread writegir 400 invalid_scope. - Hver endring registreres med både brukeren det gjelder og din handlende identitet, og svar på endringer bærer et
actedBy-felt som navngir aktøren.
Å håndtere paret. Behandle clientSecret som et produksjonspassord til en database: hemmelighetshåndtering, aldri i git, aldri i en sak eller en chat-melding, én legitimasjon per system og miljø (ikke del et par mellom test og produksjon).
Opprette legitimasjon og token i grensesnittet
Samme vei, gjort klikk for klikk i Visenas webapplikasjon: opprett en legitimasjon, bytt den i et token, hent den første posten — med hver skjerm vist. Dette er veien gjennom brukergrensesnittet, den en kundes administrator vanligvis går.
Skjermbildene viser det norske grensesnittet, fordi origos grensesnitt er norsk i alle instanser. Den engelske termen følger hver etikett i teksten, slik at også en engelsk leser finner knappen som faktisk står på skjermen.
-
Åpne siden for API-tilganger. I Visena følger du Admin → Tilgangskontroll → Administrer API-tilganger. Siden ligger på
/admin/access-control/api-credentialsog lister hver legitimasjon i instansen.
Administrer API-tilganger ligger under Admin → Tilgangskontroll. -
Opprett legitimasjonen. Klikk Ny API-tilgang. Dialogen spør om tre ting:
- Navn — fritekst, slik at du kjenner legitimasjonen igjen senere. Kall den opp etter systemet som skal holde den:
erp-sync-prodslårmy-token. - Gjelder for — Meg selv eller På vegne av en annen. Velger du den siste, kommer det fram en personvelger, og den personen blir legitimasjonens aktør: API-klienten utfører alt som vedkommende, med nøyaktig den tilgangen vedkommende har i origo, mens du står som oppretter. Steg 4 under viser hvordan valget ser ut i oversikten.
- Tilgang — Les og skriv eller Bare lesing. Dette er taket på alt legitimasjonen noen gang kan utstede, og det kan ikke endres etterpå: velg Bare lesing når integrasjonen aldri skal skrive, så kan den heller ikke få et token som gjør det. To tak, ikke ett forklarer forholdet til scopet du ber om per token.
Deretter Opprett.
Dialogen Ny API-tilgang. Undertittelen advarer med én gang: «Hemmeligheten vises bare én gang» — og Tilgang er valget som ikke kan endres etterpå. Personnavnet er sladdet her. - Navn — fritekst, slik at du kjenner legitimasjonen igjen senere. Kall den opp etter systemet som skal holde den:
-
Kopier klient-id-en og hemmeligheten. Legitimasjonen er opprettet, og Visena viser de to verdiene OAuth 2.0-flyten trenger:
- Klient-ID — identifiserer legitimasjonen. Dette er din
client_id. - Klienthemmelighet — en
vco_…-verdi som virker som passordet. Dette er dinclient_secret.
✓Kopier hemmeligheten før du lukker dialogen. Visena lagrer bare en enveis hash, så dette er det ene øyeblikket den finnes i lesbar form. Legg den rett i hemmelighetshåndteringen din. Blir den mistet, finnes det ingen visning og ingen nullstilling: opprett en ny legitimasjon og trekk tilbake denne.
Engangsdialogen Tilgangen er opprettet — kopier begge verdiene nå. - Klient-ID — identifiserer legitimasjonen. Dette er din
-
Vær klar over hvem tokenet handler som. Hver legitimasjon er knyttet til en brukeridentitet, og kall som gjøres med tokenene den utsteder, handler som den brukeren, med den brukerens rettigheter. Valget Gjelder for fra steg 2 avgjør hvem det er:
Valg Tokenet autentiserer som Meg selv
MyselfPersonen som opprettet legitimasjonen. Aktør og Opprettet av navngir da den samme personen — deg. På vegne av en annen
On behalf of someone elseBrukeren du valgte. Oversikten viser vedkommende under Aktør og deg under Opprettet av. Tokener for slike legitimasjoner må hentes med act-as-user:…-scopene; se legitimasjon på vegne av en annen.Oversikten lister hver legitimasjon med navn, klient-id, Aktør, Tilgang, status, Sist brukt — satt når et token fra legitimasjonen brukes mot API-et, ikke når tokenet ble hentet — samt når den ble opprettet og av hvem:
Aktør er identiteten tokenet handler som — kolonnen å sjekke før du tar en legitimasjon i bruk. Klient-id-ene og personnavnene er sladdet her; på skjermen står de i klartekst. -
Bytt legitimasjonen i et token. POST paret til gatewayens token-endepunkt med standard OAuth 2.0-grant-typen
client_credentials. Skjermbildene under sender legitimasjonen i skjemakroppen, som er det en API-klient gjør som standard; i produksjon er HTTP Basic den anbefalte formen — begge er dekket under token-forespørselen.EndepunktPOST {baseUrl}/{instanceName}/auth/api/v1/token Content-Type: application/x-www-form-urlencodedFelt Verdi grant_typeclient_credentialsscopeHva tokenet får gjøre: read,writeellerread write. Obligatorisk — det finnes ingen standardverdi.client_idKlient-ID fra steg 3 client_secretKlienthemmelighet fra steg 3 iSkal du bare lese? Be om
scope=read. Et slikt token kan aldri endre noe, uansett hva den underliggende brukeren har lov til — Skrivebeskyttet tilgang viser garantien håndhevet, med 403-en som beviser det.Forespørsel — curlcurl -X POST https://api.visena.example/acme/auth/api/v1/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "scope=read" \ -d "client_id=<your Klient-ID>" \ -d "client_secret=<your Klienthemmelighet>"Svar — 200 OK{ "access_token": "dcrEUVpMEpYqbdsDKawBb1yTqIAELMgqIO4KrN…", "scope": "read", "token_type": "Bearer", "expires_in": 86399 }
Token-forespørselen i en API-klient — merk scope: readbåde i forespørselen og i svaret.
Samme forespørsel som en generert curl-kommando. Dette skjermbildet peker på en lokal utviklings-gateway; din er base-URL-en fra onboardingen. Tokenet er opakt, lever i
expires_insekunder, og det finnes ikke noe refresh token: når det utløper, gjentar du forespørselen. Cache tokenet har mønsteret, og feiltabellen hele listen over feil fra token-endepunktet. -
Gjør det første kallet. Send tokenet som en Bearer-header til ressursserveren gjennom samme gateway. Stien bærer instansnavnet, API-versjonen og locale-segmentet — her hentes én person:
Forespørsel — curlcurl "https://api.visena.example/acme/api/v1/en/person/KDiJs47rD4THRo5uPwlESr0" \ -H "Authorization: Bearer <access_token>"
En person hentet gjennom gatewayen — ren JSON, autentisert av Bearer-headeren alene.
Samme kall som en generert curl-kommando.
Det er hele runden: legitimasjon → token → kall. Videre herfra dekker Å gjøre kall URL-anatomi, maskerte id-er, locale-segmentet og formene hvert endepunkt returnerer, og Skrivebeskyttet tilgang dekker hva scope=read utelukker.
Hente et access token
Én standard OAuth 2.0-forespørsel gjør legitimasjonen din om til et kortlevd bearer-token, avgrenset til nøyaktig det du ber om.
Token-forespørselen
POST til /{instanceName}/auth/api/v1/token med grant-typen client_credentials. Det er hele stien: instansnavnet, så den faste autentiseringsflaten auth/api/v1, så token — uten locale-segment, og ingenting imellom. Autentiser med HTTP Basic (anbefalt) eller med skjemafeltene client_id/client_secret — begge er standard OAuth 2.0.
curl -X POST https://api.visena.example/acme/auth/api/v1/token \
-u "acme-partner-3f9a:$CLIENT_SECRET" \
-d "grant_type=client_credentials" \
-d "scope=read write"
{
"access_token": "PhVYGf3qK9t2Zx0CmW8rNbL5aTuJdEwSyAoQiHkXgMfDzUcRvBnOl46E…",
"scope": "read write",
"token_type": "Bearer",
"expires_in": 86399
}
access_tokener opakt — en uleselig streng, ikke en JWT. Prøv aldri å dekode eller inspisere det; bare send det tilbake som en bearer-header.expires_iner sekunder til utløp. Les det fra svaret hver gang — kod aldri inn en levetid.- Det finnes ikke noe refresh token. Når tokenet utløper, kjører du samme forespørsel på nytt.
Å sette scopes — reglene
Scope er obligatorisk og eksplisitt. En token-forespørsel uten scope-parameter avvises med 400 invalid_scope — plattformen gjetter aldri hva du mente å be om.
Du kan be om legitimasjonens fulle scope-sett eller et hvilket som helst delsett av det:
| Legitimasjonen din | Registrert for | Gyldige scope-verdier |
|---|---|---|
| Vanlig · Les og skriv | read write | read write · read · write |
| Vanlig · Bare lesing | read | read |
| På vegne av · Les og skriv | act-as-user:read act-as-user:write | act-as-user:read act-as-user:write · act-as-user:read · act-as-user:write |
| På vegne av · Bare lesing | act-as-user:read | act-as-user:read |
Be om read for eksportjobber og dashbord, og om skrivescopet bare i jobbene som faktisk endrer noe.
Å be om et scope legitimasjonen din ikke har — inkludert å be en på-vegne-av-legitimasjon om ren read write — gir 400 invalid_scope. Scopene håndheves deretter per kall: GET-er trenger read-scopet, alle endringer trenger write-scopet. Et token utstedt med bare read får 403 på hver POST/PUT/PATCH/DELETE.
Cache tokenet, ikke hamre på endepunktet
Hent én gang, gjenbruk til kort før utløp, hent så på nytt. En sikkerhetsmargin på 60 sekunder absorberer klokkeavvik og kall som er underveis:
const baseUrl = "https://api.visena.example";
const instanceName = "acme";
let cachedToken = null;
let cachedTokenExpiresAt = 0;
async function getAccessToken() {
if (cachedToken && Date.now() < cachedTokenExpiresAt - 60_000) {
return cachedToken;
}
const basicAuth = Buffer
.from(`${process.env.VISENA_CLIENT_ID}:${process.env.VISENA_CLIENT_SECRET}`)
.toString("base64");
const response = await fetch(`${baseUrl}/${instanceName}/auth/api/v1/token`, {
method: "POST",
headers: {
"Authorization": `Basic ${basicAuth}`,
"Content-Type": "application/x-www-form-urlencoded"
},
body: "grant_type=client_credentials&scope=read%20write"
});
if (!response.ok) {
throw new Error(`token request failed: ${response.status}`);
}
const token = await response.json();
cachedToken = token.access_token;
cachedTokenExpiresAt = Date.now() + token.expires_in * 1000;
return cachedToken;
}
Når token-endepunktet sier nei
Feil fra token-endepunktet bruker den standard OAuth 2.0-feilkroppen — { "error": "…", "error_description": "…" }:
| Status | Feil | Betydning · hva du gjør |
|---|---|---|
| 401 | invalid_client |
Feil client_id/client_secret, eller legitimasjonen er trukket tilbake. Sjekk paret; er det rotert, rull ut det nye. |
| 400 | invalid_scope |
Scope mangler, eller legitimasjonen har det ikke. Oppgi nøyaktig de scopene du trenger. |
| 400 | invalid_request / invalid_grant |
Feilformet skjemakropp eller feil grant_type — den må være client_credentials. |
| 404 | — | Ukjent instansnavn i URL-en. Kontroller det første stisegmentet. |
| 502 / 503 | — | Midlertidig plattformproblem — prøv igjen med eksponentiell backoff. |
Den OAuth-feilkroppen er token-endepunktets egen form. Alt bak tokenet — forretnings-API-et du kaller med det — svarer i stedet med RFC 9457-problemdokumenter; se Feil og feilsøking.