Denne guide er til softwareudbydere, læringsportaler og udviklere af egne webapps, der vil tilbyde "Log ind med Unilogin" uden selv at have en aftale med STIL.
OpenSSO er en OpenID Connect-udbyder. Vi understøtter Authorization Code-flowet, hvor
PKCE med S256 er påkrævet. Brugeren logger ind med Unilogin hos STIL via OpenSSO,
og jeres app modtager et id_token. I behøver ingen aftale med STIL.
client_id og et client_secret.De fleste OpenID Connect-biblioteker kan konfigurere sig selv ud fra discovery-dokumentet:
https://opensso.dk/.well-known/openid-configuration
| Endpoint | Formål |
|---|---|
/oidc/authorize | Starter login: brugeren sendes hertil (authorization endpoint). |
/oidc/token | Veksler authorization code til id_token og access_token (kun POST). |
/oidc/userinfo | Returnerer claims for access_token (Bearer). |
/oidc/jwks | Offentlige nøgler (JWKS), som id_token verificeres mod. |
/oidc/logout | Afslutter sessionen hos OpenSSO og sender brugeren tilbage til jer. |
client_secret_basic eller client_secret_post.grant_type=authorization_code. Der udstedes ingen refresh tokens.access_token er gyldigt i 1 time.id_token er signeret med RS256 og verificeres mod nøglerne på /oidc/jwks (match på kid). Tjek at aud er jeres client_id og iss er https://opensso.dk.Scopes skal være godkendt på jeres integration. Scopes, I ikke har fået godkendt, udelades stille.
| Scope | Claims |
|---|---|
openid | sub |
profile | name, given_name, family_name |
unilogin | uniid |
skole | aktoer_gruppe, institution_ids, inst_brugere, elevtrin, hovedgruppenavn, roller, grupper, has_license |
sub er altid pairwise og pseudonym: en tilfældig, stabil ID pr. bruger pr. app,
som gemmes i OpenSSOs database. Samme elev får forskellig sub i forskellige apps, og jeres app kan ikke se
Unilogin-brugernavn eller navn, medmindre scopes unilogin eller profile er godkendt på integrationen.
Det betyder, at en app kan nøjes med scope openid og alligevel genkende brugeren næste gang - uden
egen "anonymiserings"-server eller database til ID-kobling.
Først genereres en PKCE-verifier og -challenge (gem verifier, state og nonce i brugerens session):
# code_verifier: 43-128 tegn (a-z A-Z 0-9 - . _ ~), gemmes i sessionen
CODE_VERIFIER=$(openssl rand -base64 48 | tr '+/' '-_' | tr -d '=\n')
CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')
Send derefter brugeren til authorize-URL'en (linjeskift er kun for læsbarhed):
https://opensso.dk/oidc/authorize
?response_type=code
&client_id=DIT_CLIENT_ID
&redirect_uri=https%3A%2F%2Fapp.example.dk%2Fcallback
&scope=openid%20profile
&state=TILFAELDIG_STATE
&nonce=TILFAELDIG_NONCE
&code_challenge=BASE64URL(SHA256(code_verifier))
&code_challenge_method=S256
Brugeren sendes tilbage til jeres redirect-URI med code og state.
Kontrollér at state matcher, og byt koden til tokens:
curl -X POST https://opensso.dk/oidc/token \
-u "DIT_CLIENT_ID:DIN_CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code=KODEN_FRA_CALLBACK \
-d redirect_uri=https://app.example.dk/callback \
-d code_verifier="$CODE_VERIFIER"
{
"token_type": "Bearer",
"access_token": "...",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ii4uLiJ9..."
}
Verificér id_token (signatur mod JWKS, iss, aud, exp og at nonce er den, I sendte).
composer require jumbojett/openid-connect-php
<?php
require __DIR__.'/vendor/autoload.php';
use Jumbojett\OpenIDConnectClient;
session_start();
$oidc = new OpenIDConnectClient('https://opensso.dk', 'DIT_CLIENT_ID', 'DIN_CLIENT_SECRET');
$oidc->setRedirectURL('https://app.example.dk/callback');
$oidc->setCodeChallengeMethod('S256'); // PKCE er påkrævet
$oidc->addScope(['openid']); // tilføj 'profile', 'unilogin', 'skole' hvis godkendt
$oidc->authenticate(); // sender brugeren til OpenSSO og håndterer callback
// id_token er verificeret (signatur, iss, aud, exp, nonce)
$sub = $oidc->getVerifiedClaims('sub');
$idToken = $oidc->getIdToken(); // gem til logout
// npm install openid-client@5
import { Issuer, generators } from 'openid-client';
const issuer = await Issuer.discover('https://opensso.dk');
const client = new issuer.Client({
client_id: 'DIT_CLIENT_ID',
client_secret: 'DIN_CLIENT_SECRET',
redirect_uris: ['https://app.example.dk/callback'],
response_types: ['code'],
// token_endpoint_auth_method er som standard client_secret_basic
});
// 1. Start login (gem verifier, state og nonce i brugerens session)
const codeVerifier = generators.codeVerifier();
const state = generators.state();
const nonce = generators.nonce();
const url = client.authorizationUrl({
scope: 'openid profile',
state,
nonce,
code_challenge: generators.codeChallenge(codeVerifier),
code_challenge_method: 'S256',
});
// redirect brugeren til url
// 2. Callback (fx Express: req.query indeholder code og state)
const params = client.callbackParams(req);
const tokenSet = await client.callback(
'https://app.example.dk/callback',
params,
{ code_verifier: codeVerifier, state, nonce },
);
const claims = tokenSet.claims(); // verificeret id_token
console.log(claims.sub);
Send brugeren til /oidc/logout med id_token_hint,
en registreret post_logout_redirect_uri og en state:
https://opensso.dk/oidc/logout
?id_token_hint=ID_TOKEN
&post_logout_redirect_uri=https%3A%2F%2Fapp.example.dk%2Flogget-ud
&state=TILFAELDIG_STATE
Med jumbojett i PHP:
$oidc->signOut($idToken, 'https://app.example.dk/logget-ud');
error=access_denied: brugeren afbrød loginet hos STIL. Vis en venlig besked og lad brugeren prøve igen.error=login_required: returneres ved prompt=none, når brugeren ikke allerede har en session hos OpenSSO.
Det eksisterende WordPress-plugin bruger et enklere handoff:
brugeren sendes til en start-URL hos OpenSSO og tilbage til jeres side med et JWT signeret med HS256 og en delt hemmelighed.
Tokenet er gyldigt i 60 sekunder, og jti er et engangs-id, som modtageren skal afvise ved genbrug.
Claims (felter uden værdi er null):
{
"iss": "https://opensso.dk",
"jti": "unikt-id-pr-token",
"aud": "jeres-integrations-token",
"iat": 1700000000,
"exp": 1700000060,
"sub": "...", "uniid": "...", "institution_ids": [...],
"aktoer_gruppe": "...", "has_license": true
}
Til nye integrationer anbefaler vi OpenID Connect ovenfor.
Kræver en tredjepart ikke OIDC, men et signeret link med et anonymt bruger-id, kan OpenSSO oversætte jeres bruger-id til et tilfældigt, stabilt pseudonym og sende browseren videre.
Jeres side sender brugeren til GET /videresend/{integration_token}?userID=…×tamp=…&hash=…, hvor
hash er hex(HMAC-SHA256(delt hemmelighed, "{userID}&{timestamp}")). Linket er gyldigt i 120 sekunder og kan kun bruges én gang.
OpenSSO videresender til tjenesten med pseudonymet, et nyt timestamp og en ny signatur - jeres bruger-id forlader aldrig OpenSSO.
Nej. I får jeres integration hos OpenSSO, og vi står for forbindelsen til Unilogin hos STIL. I behøver ikke selv være tilsluttet STIL eller have en dataaftale for at bruge OpenID Connect-integrationen.
Se vores prisside eller kontakt os, så finder vi den rigtige løsning til jeres behov. Se priser.
Ja. Vi opretter en testintegration mod STILs testmiljø, så I kan afprøve hele loginflowet med testbrugere, før I skifter til produktion.
Skriv til info@opensso.dk eller kontakt Torben Langelund Sørensen direkte på torben@opensso.dk / +45 2750 7430.
Vi bruger kun statistik-cookies, hvis du accepterer det - læs mere i vores cookiepolitik.