{
  "schema_version": "1.0",
  "name": "Mercantec Auth",
  "purpose": "OAuth 2.0 authorization server med PKCE, JWT (RS256) og refresh tokens til Mercantec-platforme.",
  "platform_attribution": {
    "maintainer": "MAGS",
    "role": "underviser",
    "contact_email": "mags@mercantec.dk",
    "notice_da": "Denne installation er et undervisningsprojekt ved MAGS og er ikke Mercantecs officielle produktions-login. Kontakt mags@mercantec.dk ved sp\u00F8rgsm\u00E5l."
  },
  "email_password_login_enabled": false,
  "auth_configuration_note": "Auth:EnableEmailPasswordLogin (eller milj\u00F8variabel Auth__EnableEmailPasswordLogin) styrer e-mail/adgangskode p\u00E5 /Account/Login, /Account/Register og POST /signin, /signup.",
  "audience_for_this_document": [
    "Udviklere der tilslutter en ny webapp, mobilapp eller backend.",
    "AI-agenter der skal generere korrekt login- og API-kode mod Mercantec Auth."
  ],
  "issuer": "https://auth.mercantec.tech",
  "jwt": {
    "algorithm": "RS256",
    "issuer_must_equal": "https://auth.mercantec.tech",
    "audience_must_equal": "mercantec-apps",
    "access_token_lifetime_minutes": 15,
    "refresh_token_lifetime_days": 30,
    "jwks_uri": "https://auth.mercantec.tech/.well-known/jwks.json",
    "validate_signature_against_jwks": true,
    "standard_claims": [
      {
        "claim": "sub",
        "meaning": "Brugerens stabile GUID som streng."
      },
      {
        "claim": "name",
        "meaning": "Vist navn."
      },
      {
        "claim": "email",
        "meaning": "E-mail n\u00E5r den findes p\u00E5 brugeren."
      },
      {
        "claim": "login_method",
        "meaning": "Sidste login: password, google, github, discord, microsoft-work, \u2026"
      },
      {
        "claim": "role",
        "meaning": "Rolle (gentaget claim pr. rolle). Bruges til autorisation i jeres API."
      },
      {
        "claim": "iss",
        "meaning": "JWT-udsteder \u2014 skal matche issuer_must_equal."
      },
      {
        "claim": "aud",
        "meaning": "Audience \u2014 skal matche audience_must_equal."
      },
      {
        "claim": "exp",
        "meaning": "Udl\u00F8b (Unix sekunder)."
      },
      {
        "claim": "iat",
        "meaning": "Udstedt (Unix sekunder)."
      }
    ],
    "dotnet_role_claim_type": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
  },
  "oauth2": {
    "flows_supported": [
      "authorization_code"
    ],
    "grant_types": [
      "authorization_code",
      "refresh_token"
    ],
    "response_types": [
      "code"
    ],
    "pkce": {
      "required": "Ja for klienter hvor RequirePkce er sand i databasen (anbefalet for alle offentlige SPA\u0027er).",
      "code_challenge_method": "S256",
      "code_challenge": "BASE64URL(SHA256(code_verifier)) uden padding",
      "code_verifier": "Kryptografisk tilf\u00E6ldig streng (RFC 7636)"
    },
    "endpoints": {
      "authorization": "https://auth.mercantec.tech/oauth/authorize",
      "token": "https://auth.mercantec.tech/oauth/token"
    },
    "authorize_query_parameters": [
      {
        "name": "response_type",
        "value": "code",
        "required": true
      },
      {
        "name": "client_id",
        "required": true
      },
      {
        "name": "redirect_uri",
        "required": true,
        "note": "Skal matche en registreret URI pr\u00E6cist (whitelist)."
      },
      {
        "name": "state",
        "required": false,
        "note": "St\u00E6rkt anbefalet mod CSRF."
      },
      {
        "name": "code_challenge",
        "required": true,
        "note": "N\u00E5r PKCE er p\u00E5kr\u00E6vet for klienten."
      },
      {
        "name": "code_challenge_method",
        "value": "S256",
        "required": true,
        "note": "N\u00E5r PKCE er p\u00E5kr\u00E6vet."
      }
    ],
    "token_endpoint": {
      "method": "POST",
      "content_type": "application/x-www-form-urlencoded",
      "authorization_code_body": {
        "grant_type": "authorization_code",
        "code": "Autorizationskode fra redirect til redirect_uri",
        "redirect_uri": "Samme v\u00E6rdi som ved /oauth/authorize",
        "client_id": "Registreret client id",
        "code_verifier": "PKCE-verifier (offentlig klient)",
        "client_secret": "Kun for fortrolige (confidential) klienter \u2014 sendes i form body"
      },
      "refresh_token_body": {
        "grant_type": "refresh_token",
        "refresh_token": "Seneste refresh_token fra forrige token-svar",
        "client_id": "Registreret client id",
        "client_secret": "Kun for fortrolige klienter"
      },
      "token_response_json_fields": [
        "access_token (Mercantec JWT)",
        "refresh_token (roterende opaque token)",
        "token_type (Bearer)",
        "expires_in (sekunder)",
        "microsoft_access_token (valgfri \u2014 Azure AD til Graph n\u00E5r bruger loggede ind med Microsoft)",
        "microsoft_expires_in (valgfri)"
      ]
    }
  },
  "session_and_logout": {
    "note": "Brugeren f\u00E5r session-cookie p\u00E5 auth-hosten under login. N\u00E6ste /oauth/authorize kan derfor springe login-UI over.",
    "signout_get": "https://auth.mercantec.tech/signout",
    "signout_query_returnUrl": {
      "name": "returnUrl",
      "rules": [
        "Relativ sti (/...) redirecter p\u00E5 auth-hosten.",
        "Absolut http(s)-URL kun hvis origin er whitelisted i Cors:SpaOrigins (samme liste som CORS for jeres SPA)."
      ],
      "example_spa": "https://auth.mercantec.tech/signout?returnUrl={encodeURIComponent(\u0027https://din-app.example/\u0027)}"
    },
    "recommendation_for_spas": "Ryd lokale tokens (fx sessionStorage), derefter fuld browser-navigation til /signout?returnUrl=... tilbage til jeres app."
  },
  "browser_login_ui": "https://auth.mercantec.tech/Account/Login",
  "health": "https://auth.mercantec.tech/health",
  "this_manifest": "https://auth.mercantec.tech/.well-known/mercantec-auth.json",
  "client_registration": {
    "summary": "Hver platform skal have r\u00E6kker i ClientApps og ClientAppRedirectUri med pr\u00E6cis redirect_uri.",
    "public_client": "IsPublic=true, ingen client_secret, PKCE p\u00E5kr\u00E6vet hvis RequirePkce er sat.",
    "confidential_client": "client_secret hashes med BCrypt i databasen; send secret i token-kald.",
    "development": "I Development milj\u00F8 oprettes ofte en demo-klient automatisk \u2014 se server-dokumentation."
  },
  "cors": {
    "setting": "Cors:SpaOrigins",
    "purpose": "Browser-fetch til /oauth/token og besl\u00E6gtede API\u0027er fra jeres SPA-origin."
  },
  "checklist_new_platform": [
    "Registr\u00E9r client_id og alle produktions- og udviklings-redirect_uri\u0027er i databasen (eksakt match, inkl. trailing slash hvis relevant).",
    "Implement\u00E9r authorization code flow med PKCE S256 i frontend eller native app.",
    "Gem access_token og refresh_token sikkert (browser: overvej sessionStorage vs memory; undg\u00E5 localStorage til refresh hvis muligt).",
    "Valider Mercantec JWT p\u00E5 backend med JWKS (issuer, audience, signatur, exp).",
    "Brug Authorization: Bearer \u003Caccess_token\u003E mod jeres egne API\u0027er; tjek rolle-claims for admin m.m.",
    "Implement\u00E9r refresh f\u00F8r exp eller ved 401; brug nyt refresh_token fra hvert refresh-svar.",
    "Tilf\u00F8j jeres SPA-origin til Cors:SpaOrigins og brug /signout?returnUrl= for kontoskift.",
    "Hvis I skal kalde Microsoft Graph: l\u00E6s microsoft_access_token fra token-svar n\u00E5r det findes (kun ved Microsoft-login)."
  ],
  "ai_agent_briefing_da": "Mercantec Auth er en OAuth 2.0-server med authorization code \u002B PKCE (S256). Start med GET /oauth/authorize med client_id, redirect_uri, state, code_challenge og code_challenge_method=S256. Efter redirect med ?code= udveksles koden p\u00E5 POST /oauth/token med grant_type=authorization_code, code_verifier, redirect_uri og client_id. access_token er et RS256-JWT med iss=https://auth.mercantec.tech og aud=mercantec-apps; valider med https://auth.mercantec.tech/.well-known/jwks.json. refresh_token bruges med grant_type=refresh_token. Session-cookie p\u00E5 auth-dom\u00E6net g\u00F8r at brugeren kan v\u00E6re \u0027automatisk logget ind\u0027 ved n\u00E6ste authorize \u2014 brug GET /signout?returnUrl= for at logge ud af session.",
  "references": {
    "human_documentation_path_in_repo": "docs/CLIENT-INTEGRATION.md",
    "rfc_pkce": "https://datatracker.ietf.org/doc/html/rfc7636"
  }
}