Integrasjon av Altinn-app med Maskinporten
Hvordan sette opp en integrasjon mellom en Altinn-app og Maskinporten.
Denne veiledningen viser hvordan du setter opp en Altinn-app til å utføre autoriserte forespørsler med Maskinporten på vegne av eieren av appen, i stedet for den aktive brukeren.
Maskinporten-automatisering i Altinn Studio
- Apper som bruker Altinn App v8.3 eller nyere kan aktivere standardscopene for tjenesteeier,
altinn:serviceowner, altinn:serviceowner/instances.read og altinn:serviceowner/instances.write, fra Altinn Studio. Bruk knappen i Maskinporten-fanen eller legg til scopene fra scope-visningen i appinnstillingene. altinn:serviceowner markerer at klienten er et tjenesteeiersystem, mens altinn:serviceowner/instances.read og altinn:serviceowner/instances.write gir tilgang til å lese og skrive instanser som tjenesteeier.- Apper som bruker Altinn App v9 krever disse standardscopene. Altinn Studio legger dem automatisk til hvis de mangler.
- Nye apper som opprettes i Altinn Studio får disse standardscopene for tjenesteeier automatisk.
- Appen må også autorisere tjenesteeier i
App/config/authorization/policy.xml. Nye apper har denne regelen i appmalen. For eksisterende apper må du legge til eller oppdatere [org]-regelen slik at den gir read og write.
For å sette dette opp må du:
- Kontrollere at brukeren din har tilgang til Maskinporten-scopes.
- Legge til nødvendige scopes i Altinn Studio.
- Publisere appen slik at valgte scopes blir tilgjengelige for appen.
- Bruke den innebygde Maskinporten-klienten i appkoden.
Tilgang til Maskinporten-scopes
Altinn Studio bruker den innloggede Ansattporten-tilgangen din til å finne Maskinporten-scopene du kan legge til for tjenesteeierorganisasjonen.
Hvis du ikke ser noen scopes i Altinn Studio, kan brukeren din mangle tilgang til å administrere klienter for organisasjonen. Se hva du gjør hvis du ikke har tilgang, kontakt den som administrerer Maskinporten-tilganger for organisasjonen din, eller kontakt Altinn servicedesk.
Legg til scopes i Altinn Studio
Se steg-for-steg-veiledningen for å legge til Maskinporten-scopes i en app for skjermbilder av flyten i Altinn Studio.
Endringer i scopes trer i kraft neste gang appen bygges og publiseres.
Publisering og klientdetaljer
Når en app med Maskinporten-scopes publiseres, legger Altinn Studio valgte scopes inn i appbygget. Etter publisering kan appen bruke den innebygde Maskinporten-klienten med scopene som er valgt i Altinn Studio.
Du trenger ikke å håndtere klientdetaljer, JWKS-generering, rotasjon eller appkonfigurasjon selv for standard oppsett av apper.
Bruk
Appen inkluderer automatisk den innebygde IMaskinportenClient som kan brukes i tjenestene dine.
Konfigurasjonsstier
Klienten leter automatisk etter Maskinporten-konfigurasjon på standardstien “MaskinportenSettings”. Med scope-oppsettet i Altinn Studio er denne konfigurasjonen tilgjengelig for appen etter publisering.
Bruk standardstien når scopes er valgt i Altinn Studio. Egendefinerte konfigurasjonsseksjoner fylles ikke ut av scope-oppsettet i Altinn Studio, og bør bare brukes med manuelt eller eldre oppsett.
Autoriser HTTP-klienter
Typede og navngitte HTTP-klienter kan autoriseres med de tilgjengelige utvidelsesmetodene, som illustrert nedenfor.
App/Program.cs
void RegisterCustomAppServices(IServiceCollection services, IConfiguration config, IWebHostEnvironment env)
{
// ...
// For external APIs that require raw Maskinporten tokens
services.AddHttpClient<CustomClient1>().UseMaskinportenAuthorization("scope1", "scope2");
services.AddHttpClient("named-client1").UseMaskinportenAuthorization("scope1", "scope2");
// For Altinn APIs that require Altinn tokens (exchanges Maskinporten token)
services.AddHttpClient<CustomClient2>().UseMaskinportenAltinnAuthorization("scope1", "scope2");
services.AddHttpClient("named-client2").UseMaskinportenAltinnAuthorization("scope1", "scope2");
}
Manuell bruk
Hvis du trenger å hente et Maskinporten-token manuelt, kan du bruke IMaskinportenClient i tjenesten din og hente tokens med GetAccessToken- og GetAltinnExchangedToken-metodene.
public class Example(IMaskinportenClient maskinportenClient) : IProcessTaskEnd
{
public async Task End(string taskId, Instance instance)
{
var maskinportenToken = await maskinportenClient.GetAccessToken(["scope1", "scope2"]);
var altinnExchangedToken = await maskinportenClient.GetAltinnExchangedToken(["scope1", "scope2"]);
// Do something with the tokens...
}
}
Eldre manuelt oppsett
Det følgende manuelle oppsettet er bare nødvendig for eldre applikasjoner eller spesialtilfeller der Altinn Studio ikke skal opprette Maskinporten-klienten.
Noen eksisterende apper bruker en Maskinporten-klient som er opprettet manuelt i Samarbeidsportalen, og leser klientdetaljene fra tjenesteeierens Azure Key Vault. Dette oppsettet bruker ofte appspesifikke prefikser på hemmeligheter fordi Key Vault er delt mellom flere apper, for eksempel myapp--MaskinportenSettings--ClientId, og appkoden kan binde den innebygde klienten til en egendefinert konfigurasjonssti som myapp:MaskinportenSettings.
For å flytte en slik app til klientdetaljer håndtert av Altinn Studio:
- Kontroller hvilke scopes den eksisterende Maskinporten-klienten er konfigurert med i Samarbeidsportalen, og hvilke scopes appen ber om i kode.
- Legg de samme scopene til appen i Altinn Studio. Hvis appen bare trenger tjenesteeiertilgang til Altinn-instanser, bruker du standardscopene for tjenesteeier.
- Oppdater appkode som eksplisitt binder Maskinporten-konfigurasjon til en egendefinert sti. Fjern det egendefinerte
ConfigureMaskinportenClient("...")-kallet, eller endre det til å bruke MaskinportenSettings, slik at appen bruker konfigurasjonen fra Altinn Studio. - Bygg og publiser appen til TT02. Den publiserte appen får klientdetaljer for valgte scopes på standardstien
MaskinportenSettings. - Verifiser appen i TT02. Test at den kan hente Maskinporten-token, og at kall som krever innvekslede Altinn-token fortsatt fungerer.
- Gjenta publisering og verifisering i produksjon.
- Når produksjon er verifisert, kan gamle appspesifikke Key Vault-hemmeligheter og egendefinert Key Vault-konfigurasjon fjernes hvis de ikke brukes lenger. Ikke slett den gamle Maskinporten-klienten før du har verifisert at ingen andre apper eller integrasjoner bruker den.
Behold Azure Key Vault-oppsett som appen bruker for andre hemmeligheter. Hvis Maskinporten-klientdetaljer var de eneste verdiene appen leste fra Azure Key Vault, kan Azure Key Vault-konfigurasjonsprovideren og tilhørende appinnstillinger fjernes etter at migreringen er verifisert.
Hvis appen allerede bruker MaskinportenSettings fra Azure Key Vault
Etter publisering kan appen midlertidig ha to konfigurasjonskilder for de samme nøklene:
- konfigurasjonen Altinn Studio legger inn i appen ved publisering
- Azure Key Vault
Mens appen fortsatt skal bruke de gamle Key Vault-verdiene, må Azure Key Vault overstyre konfigurasjonen fra Altinn Studio. Sørg for at Azure Key Vault-provideren registreres etter kallet til ConfigureAppWebHost.
Når appen skal bruke klientdetaljene håndtert av Altinn Studio:
- fjern eller gi nytt navn til de gamle
MaskinportenSettings--...-hemmelighetene i Key Vault - fjern Azure Key Vault-oppsettet helt hvis appen ikke bruker Azure Key Vault til noe annet
- publiser appen på nytt
Tilgang til Azure Key Vault
Før du går videre med det manuelle oppsettet, må du forsikre deg om at du har tilgang til Azure Key Vault for organisasjonen din. Dette sikrer at nøklene som opprettes senere i veiledningen kan lagres riktig som hemmeligheter i Azure.
Hvis tilgang mangler, se Tilgang til logger og hemmeligheter.
Maskinporten-integrasjon
Når tilgang til å opprette hemmeligheter i Azure Key Vault er bekreftet, kan du opprette integrasjonen manuelt.
Konfigurasjon av Azure Key Vault
Når applikasjonen forberedes til å bruke hemmeligheter fra Azure Key Vault, må følgende trinn utføres:
Legg til hemmelighetene som ble hentet under konfigurasjon av Maskinporten-klienten, i Azure Key Vault:
- Base64-kodet JWT offentlig og privat nøkkelpar
- Klient-ID for integrasjonen
Det er viktig at navnet på disse hemmelighetene i Azure Key Vault tilsvarer navnet på seksjonen i appsettings-filen i kodebasen til applikasjonen. F.eks. hvis din appsettings-seksjon for Maskinporten-integrasjonen ser slik ut:
App/appsettings.json
{
"MaskinportenSettings": {
"Authority": "https://test.maskinporten.no/",
"ClientId": "",
"JwkBase64": ""
}
}
Skal hemmelighetene i Azure Key Vault ha navn som dette:
MaskinportenSettings--Authority
MaskinportenSettings--ClientId
MaskinportenSettings--JwkBase64
- For at applikasjonen skal kunne lese hemmelighetene fra Azure Key Vault, må den konfigureres til å gjøre det. Se secrets-seksjonen for å oppnå dette.
- Legg til appsettings-eksempelet ovenfor i
appsettings.{env}.json-filen.
Merk: Hemmelighetene leses av applikasjonen ved oppstart, så hvis du gjør endringer etter at applikasjonen er publisert, må du publisere applikasjonen på nytt for at de skal tre i kraft.
Key Vault-konfigurasjon
Til slutt må vi legge til Azure Key Vault-konfigurasjonsleverandøren til vår host. Dette gjøres ved å legge til den markerte koden etter ConfigureWebHostBuilder-metoden.
App/Program.cs
//...
ConfigureWebHostBuilder(IWebHostBuilder builder);
// Add Azure KV provider for TT02 & Prod environments
if (!builder.Environment.IsDevelopment())
{
builder.AddAzureKeyVaultAsConfigProvider();
}
Bakoverkompatibilitet
IMaskinportenTokenProvider
Visse eldre tjenester krever en implementering av IMaskinportenTokenProvider for å hente tokens. MaskinportenClient vil automatisk registrere denne tjenesten hvis den ikke allerede er registrert andre steder.
Altinn.ApiClients.Maskinporten
Hvis du trenger å støtte eksisterende bruk av den frittstående Maskinporten-klienten, mens du samtidig vil bruke den innebygde klienten for nye funksjoner, gir det vanligvis mening å utnytte ett felles eldre manuelt oppsett.
Eksempelet nedenfor illustrerer hvordan du kan omforme et Altinn.ApiClients.Maskinporten.Config.MaskinportenSettings-objekt til formatet som kreves av den innebygde klienten.
App/Program.cs
using Altinn.App.Core.Features.Maskinporten.Exceptions;
using LegacyMaskinportenSettings = Altinn.ApiClients.Maskinporten.Config.MaskinportenSettings;
// ...
void RegisterCustomAppServices(IServiceCollection services, IConfiguration config, IWebHostEnvironment env)
{
// ...
var legacySettings =
config.GetSection("Maskinporten-Config-Path").Get<LegacyMaskinportenSettings>()
?? throw new MaskinportenConfigurationException("Maskinporten settings not found in config.");
services.ConfigureMaskinportenClient(options =>
{
options.ClientId = legacySettings.ClientId;
options.JwkBase64 = legacySettings.EncodedJwk;
options.Authority = legacySettings.Environment switch
{
"prod" => "https://maskinporten.no/",
"test" => "https://test.maskinporten.no/",
"dev" => "https://maskinporten.dev/",
_ => throw new MaskinportenConfigurationException($"Unknown Maskinporten environment value {legacySettings.Environment}")
};
});
// More information about the Maskinporten environment mapping:
// https://github.com/Altinn/altinn-apiclient-maskinporten/blob/main/src/Altinn.ApiClients.Maskinporten/Services/MaskinportenService.cs#L343
}
Hvis du har
konfigurert MaskinportenSettings i Key Vault, må mappingen som er beskrevet i dette steget enten gjøres via forsinket utførelse eller
etter at Key Vault er lagt til som en options provider. Hvis konfigurasjonsdelegaten kjøres for tidlig, er ikke alle verdier lastet inn ennå.
Migreringsveier
I denne seksjonen finner du noen korte eksempler på hvordan du kan migrere din eksisterende konfigurasjon fra den frittstående Maskinporten-klienten til den innebygde.
Bruk av AddMaskinportenHttpClient
Følgende eksempel viser hvordan en EventSubscriptionClient tradisjonelt har blitt konfigurert, og hvordan du kan oppnå samme resultat ved å bruke den innebygde Maskinporten-klienten.
App/Program.cs
void RegisterCustomAppServices(IServiceCollection services, IConfiguration config, IWebHostEnvironment env)
{
// ...
// Before: Altinn.ApiClients.Maskinporten client configuration
services
.AddMaskinportenHttpClient<SettingsJwkClientDefinition, EventsSubscriptionClient>(
config.GetSection("Maskinporten-Config-Path"),
clientDefinition =>
{
clientDefinition.ClientSettings.Scope = "altinn:serviceowner/instances.read";
clientDefinition.ClientSettings.ExhangeToAltinnToken = true;
}
)
.AddTypedClient<IEventsSubscription, EventsSubscriptionClient>();
// After: Built-in client configuration
services.ConfigureMaskinportenClient("Maskinporten-Config-Path");
services
.AddHttpClient<IEventsSubscription, EventsSubscriptionClient>()
.UseMaskinportenAltinnAuthorization("altinn:serviceowner/instances.read");
}
Bruk av AddMaskinportenHttpMessageHandler
Følgende eksempel viser hvordan Altinn.ApiClients.Dan typisk har blitt konfigurert, og hvordan du kan oppnå samme resultat ved å bruke den innebygde Maskinporten-klienten.
App/Program.cs
void RegisterCustomAppServices(IServiceCollection services, IConfiguration config, IWebHostEnvironment env)
{
// ...
// Before: Altinn.ApiClients.Maskinporten client configuration
services.RegisterMaskinportenClientDefinition<SettingsJwkClientDefinition>(
"client-name",
config.GetSection("Maskinporten-Config-Path")
);
services
.AddDanClient(config.GetSection("Dan-Config-Path"))
.AddMaskinportenHttpMessageHandler<SettingsJwkClientDefinition>(
"client-name",
clientDefinition =>
{
clientDefinition.ClientSettings.Scope = "altinn:dataaltinnno";
}
);
// After: Built-in client configuration
services.ConfigureMaskinportenClient("Maskinporten-Config-Path");
services
.AddDanClient(config.GetSection("Dan-Config-Path"))
.UseMaskinportenAuthorization("altinn:dataaltinnno");
}