Versjon 1.0 - Bjørn Dybvik Langfors, sist endret: 15. Aug 2024, kl. 19:56:02 (se git-historikk)

Introduksjon

I dette dokumentet beskrives et konsept for hvordan tjenester, som i denne konteksten er begrenset til dialog- og meldingstjenester, kan nyttiggjøre seg av fellesfunksjonalitet i økosystemet av Altinn-produkter, herunder dagens “innboks”, sluttbrukers arkiv, autorisasjon, varsling og hendelser uten at det innebærer behov for å benytte seg av Altinns utviklingsmiljøer eller applikasjonskjøretidsmiljø. Alle interaksjoner mellom tjenestetilbydere og denne løsningen foregår via API-er, og det legges opp til stor fleksibilitet i hvorvidt løsningen involveres og bestrebes minst mulig begrensninger på hvordan forretningslogikken eller ulike brukerflater hos tjenestetilbyder realiseres.

Scenarioer som påvirker Dialogporten

Det er typisk tre scenarioer som innebærer behov for interaksjon med Dialogporten og dialoger.

  1. Sluttbruker-initiert dialog, hvor sluttbruker (på vegne av seg selv eller annen part) finner og starter tjeneste ved hjelp av
    • Offentlig tjenestekatalog
    • Søkemotor
    • Etatenes nettsider
    • SBS (enten manuelt eller fordi SBS agerer på en hendelse
      Dette fører til at tjenestetilbyder oppretter en dialog i Dialogporten som tilhører den aktuelle mottakeren.
  2. Tjenestetilbyder-initiert dialog, hvor tjenestetilbyder oppretter dialogen selv i Dialogporten som tilhører den aktuelle mottakeren. Dette er typisk:
    • «Prefill»-scenarioer, hvor tjenestetilbyderen trenger å innhente opplysninger og gir aktøren et delvis forhåndsutfylt skjema å begynne med
    • Proaktive/sammenhengende tjenester, hvor en tjenestetilbyder igangsetter en dialog som følge av en hendelse (som kan ha oppstått i en annen tjeneste)
  3. Sending av digital post
    • DPV, DPI
    • Typisk én-veis (foruten «rekommandert»-funksjonalitet hvor tjenestetilbyder trenger bekreftelse på at melding er mottatt og lest)
    • Ikke-muterbar - meldingen forandrer seg ikke etter at den er mottatt (annet enn «lest»-status og arkiv/slettet-tilstand)
    • Kan være utgangspunkt for sluttbruker-initiert dialog, med lenker til «neste trinn»
    • Teknisk/funksjonelt subset av tjenestetilbyder-initiert dialog, men kan også være del av en sluttbruker-initiert dialog (f.eks. et vedtaksbrev)

Viktige begreper

GUI

“Graphical User Interface”, som på norsk kan oversettes til grafisk brukergrensesnitt. Typisk en webløsning som konsumeres gjennom en nettleser, men kan også være f.eks. et fagsystem i form av en desktop-applikasjon eller en mobil app.

API

“Application Programming Interface”, maskinelt grensesnitt som gjør det mulig for ulike systemer å kommunisere med hverandre.

Dialogporten

Dialogporten benyttes for å betegne det overordnede konseptet som beskrives i dette dokumentet, prosjektet/tiltaket som utarbeidet konseptet, samt teamet som jobber med å realisere det.

Dialogporten benyttes også som navn på løsningskomponenten (produktet) som tilbyr API for enhetlig tilgang og håndtering av digitale dialoger til Felles Arbeidsflate(r) og Sluttbrukersystemer, inkludert lagring av metadata om dialogene, og som dekker Altinn Platform-funksjonalitet for tilgangsstyring og -kontroll, hendelser og varsling.

Felles Arbeidsflate

Felles Arbeidsflate refererer til en tenkt implementasjon av et GUI som benytter seg av Dialogporten, og som fungerer som en felles grafisk arbeidsflate for alle som ikke benytter et sluttbrukersystem eller et skreddersydd GUI implementert på f.eks. en etatsportal.

Sluttbrukersystem (SBS) og fagsystem

Sluttbrukersystemer og fagsystemer er begge applikasjoner som benytter seg API for å tilby et skreddersydd GUI for en eller flere grupper brukere i ulike kontekster.

Systembruker

Tilsvarede “systembruker” i Altinn 2, er en systembruker en ikke-menneskelig identitet knyttet til en virksomhet (i praksis et organisasjonsnummer) som virksomheten kan fritt opprette for å aksessere tjenester og utføre handlinger på vegne av virksomheten selv eller en eller flere av virksomhetens kunder uten menneskelig interaksjon, gjennom at den gis rettigheter i Altinn på samme måte som vanlige ansatte/personer. Kan sammenlignes med en “service principal” i Azure Active Directory.

Tjenestetilbyder

En tjenestetilbyder er en etat eller offentlig virksomhet som har behov for å føre dialog med publikum i forbindelse med forvaltning av et eller flere lovverk. I noen tilfeller er det private aktører som tilbyr tjenesten på vegne av en offentlig virksomhet.

Part

En part er en person, enten fysisk eller juridisk, som tjenestetilbyderen har dialog med.

Dialogtjeneste

En dialogtjeneste er en digital tjeneste, typisk på web, hvor tjenestetilbyderen kommuniserer med en part i forbindelse med forvaltning av et eller flere lovverk. Tradisjonelt innebærer en dialogtjeneste bruk av ulike skjema, hvor parten - gjennom et GUI levert av tjenestetilbyderen og/eller et API levert av tjenestetilbyderen og tatt i bruk av et sluttbrukersystem eller fagsystem. En dialogtjeneste har gjerne definert flere ulike trinn som typisk gjøres sekvensielt (men som i noen tilfeller kan ha parallelle “spor” som involverer flere parter).

Som det pekes på i avsnittet Scenarioer som påvirker Dialogporten vil en dialogtjeneste i denne konteksten også kunne dekke behovet tjenestetilbydere har for å kunne dele informasjon, altså det som typisk kalles “digital post”.

Dialog

Dialogen er en abstrakt og felles modell for alle pågående eller avsluttede spesialiserte dialoger hos en tjenestetilbyder, og inneholder beskrivende metadata, f.eks. hvem som er mottakende part, adresse (URL), overskrift, dato, status, en liste over aktuelle handlinger som kan utføres av brukeren samt en valgfri liste over dialogelementer. Handlinger kan vilkårlig defineres av tjenestetilbyder, og all interaksjon med den dialogen foregår i tjenestetilbyders brukerflater eller mot tjenestetilbyders API-endepunkter (unntaket er GUI-handlinger som beskriver skriveoperasjoner, se mer om dette i avsnittet Handlinger).

En viktig forskjell mot dagens «correspondence» i Altinn, er at dialogene i Dialogporten er mutérbare. Tjenestetilbyder kan når som helst oppdatere metadata og tilgjengelige handlinger på dialogen. Enhver endring fører til at det genereres hendelser, som autoriserte parter kan agere på, f.eks. at det sendes et varsel eller at et SBS foretar seg noe.

Dialoger har en UUID som identifikator. Tjenesteeier kan selv oppgi ønsket UUID ved opprettelse for å gjøre det mulig å bruke samme identifikator på tvers av systemer og for å sikre idempotens.

Spesialisert dialog

Med spesialisert dialog, refereres det til en konkret dialog (f.eks. innsending av Skattemelding) mellom en tjenestetilbyder og en eller flere parter, og som typisk refererer en saksgang eller prosess hos tjenestetilbyderen, og/eller realiserer et behov parten har for innsyn i opplysninger hos tjenestetilbyder. En spesialisert dialog kan ses på som en tilstandsfull “instans” av en dialogtjeneste. All håndtering og forretningslogikk/semantikk knyttet til en spesialisert dialog håndteres av tjenestetilbyderen.

Dialogelement

Dialogelementer utgjør distinkte bestanddeler av en dialog og kan brukes i komplekse dialoger hvor det kan være hensiktsmessig for sluttbrukere og systemer å forholde seg til enkelte deler av dialogen i tillegg til dialogen som helhet. Dette kan være meldinger og pre-utfylte skjemaer fra tjenestetilbyder, innsendte skjemaer fra parten, kvitteringer, strukturerte feilmeldinger, rapporter, ustrukturerte vedlegg til meldinger etc. som utgjør en del av den totale dialogen. Dialogelementer blir typisk referert av innslag i activityHistory. API-handlinger kan også referere et enkelt dialogelement.

Dialogelementer kan indikeres at de skal embeddes i arbeidsflate/sluttbrukersystemet, og ikke vises som en lenke som bruker foretar en navigasjon til. Disse vil da embeddes direkte i arbeidsflate, og dette foretas av nettleser i framkanal med Fetch API og ved hjelp av Dialogtoken og kalles “front channel embeds”.

Prosess-identifikator

(Tidligere kalt “dialoggruppe”) Enkelte typer saksganger består av flere distinkte delprosesser/dialoger som ikke enkelt eller hensiktsmessig kan knyttes til en og samme dialog, f.eks. når det er ulike dialoger som må gjennomføres med ulike tjenesteeiere og som ikke nødvendigvis skal foregå sekvensielt.

Alle dialoger kan referere en prosess-identifikator, som knytter disse sammen. En prosess-identifikator er ikke en egen entitet, men er en rik attributt på dialogen som lar GUI-implementasjoner gruppere/sammenknytte dialoger som logisk hører sammen.

Dialogtoken (DT)

Et dialogtoken er et signert JSON Web Token (JWT) som inneholder informasjon om den autentiserte brukeren/organisasjonen, hvilken aktør som er valgt, identifikator til dialogen, dato og andre opplysninger. Les mer i avsnittet om dialogtoken.

Hendelser

Hendelser refererer til tekniske applikasjonshendelser som genereres av Dialogporten (eller tjenestetilbyder) og publiseres gjennom Event-komponenten i Altinn. Hendelser kan konsumeres av autoriserte parter og tjenestetilbyder, i tråd med de autorisasjonsregler tjenestetilbyder har definert.

Se også Integrasjon med event-komponenten for tekniske detaljer.

Handlinger

En handling (som i «action») beskriver en interaksjon som brukere kan gjøre med eller relatert til en dialog. Eksempler på handlinger er «Åpne», «Arkiver», «Slett», «Start signering», «Betal», «Bekreft», «Les mer» etc. Listen over aktuelle handlinger er en del av den strukturerte beskrivelsen av en dialogen, og kan når som helst endres av tjenestetilbyder gjennom API.

En handling er enten en «GUI»-handling eller en «API»-handling. Alle handlinger - både GUI og API - har en identifikator som mappes til en action (og valgfritt et autorisasjonsattributt, indikert av feltet authorizationAttribute) i autorisasjonspolicyen (XACML) som er knyttet til en tjenesteressurs.

GUI-handlinger

GUI-handlinger gjøres synlige for brukeren i form av knapper, lenker eller lignende. Tjenestetilbyderen oppgir selv om en gitt handling er å regne som en primær-, sekundær eller tertiær-handling, noe som påvirker hvordan dette presenteres til brukeren. En primærhandling vil typisk presenteres som en fremhevet knapp («call to action»), og benyttes for det som er det logiske neste steget. En sekundærhandling (f.eks. «Avbryt») kan være en mer nedtonet knapp, eller tekstlenker, mens en tertiærhandling (f.eks. «Les mer om denne tjenesten») kan gjemmes bak en nedtrekksmeny eller lignende. Alt dette vil være opp til det aktuelle GUI-et som benyttes å vurdere, og ulike vurderinger vil kunne gjøres avhengig av “view” - altså kontekst, tenkt brukergruppe m.m. Det vil være begrensninger på hvor mange GUI-handlinger som kan defineres av de ulike typene.

Alle GUI-handlinger har en URL. Disse URLene brukes i framkanal når brukeren aktiverer den aktuelle handlingen, og innebærer at brukeren blir omdirigert til tjenestetilbyderens egen brukerflate hvor den aktuelle handlingen da utføres, enten automatisk eller gjennom videre brukerinteraksjon. Denne omdirigeringen skjer alltid med en GET, som sikrer at eventuelle sesjoner som allerede eksisterer hos tjenestetilbyder blir benyttet (altså at nettlesere vil sende sesjonscookies), eller at omdirigering via SSO-innlogging i ID-porten fungerer. Disse URL-ene må altså returnere enten omdirigeringer eller HTML, og siden det er GET anbefales det ikke at disse handlingene direkte medfører tilstandsendringer.

GUI-handlinger kan imidlertid markeres at de er skriveoperasjoner, og kan da også brukes for å gjennomføre tilstandsendringer. Brukeren blir da ikke omdirigert, men arbeidsflate/GUI vil da foreta en (tom) POST- eller DELETE-forespørsel på vegne av brukeren til den oppgitte URL-en i framkanal, og oppgi dialogtoken som autorisasjonsmiddel. Avhengig av konfigurasjon, vil sluttbrukere blir presentert med en oppdatert dialog-visning. Ved feil (enten av tekniske eller forretningslogiske årsaker) kan en feilmelding vises, enten basert på den faktisk responsen eller predefineres i dialogen.

Dialogporten/arbeidsflate har ikke logikk knyttet til actions, så for handlinger som innebærer komplekse muteringen av dialogen, må tjenesteeier oppdatere dialogen i bakkanal og returnere en 2xx-respons i requesten som ble kalt i fremkanal. I disse tilfellene må det konfigureres at arbeidsflate/GUI skal laste dialogen på nytt etter mottatt 2xx-respons. Her vil Dialogporten støtte SignalR-basert notififkasjon, slik at arbeidsflate kan vise spinner frem til dialogen er blitt oppdatert og laste den på nytt da.

Det vil også være mulig å indikere til sluttbrukersystem/SBS at endringen ikke skjer umiddelbart, slik at det kan vises en eller annen predefinert melding umiddelbar og at dialogen/aktuell knapp skal skjules i GUI. Merk at sluttbruker ikke vil kunne mutere dialogen gjennom sluttbruker-API-et, annet enn det som går på merking (labelling) av dialogen. Denne håndteringen kan da persisteres i sluttbrukers local storage inntil endringen av dialogen faktisk har funnet sted.

API-handling

En API-handling er tiltenkt SBS-er og portaler som benytter Dialogporten gjennom en egen integrasjon, og gjør det mulig å definere handlinger som medfører tilstandsendringer og som tar kompleks input som ikke direkte kan gjennomføres med en nettleser pga. sikkerhetsmekanismer i disse. API-handlinger er versjonerte, og inneholder en liste med endepunkter som kan kalles, evt. med informasjon om et endepunkt er under utfasing og når dette vil skje. Hver handling inneholder også en identifikator som indikerer hva slags type handling det er snakk om, og hvert endepunkt indikerer hvilken URL som må kalles for å utføre handlingen. Endepunktet inneholder også informasjon om hvilken HTTP-operasjon som skal benyttes (typisk GET eller POST), og valgfritt en lenke til en strukturert beskrivelse (JSON Schema) av datamodellen som enten returneres eller forventes som input, som kan brukes for dokumentasjonsformål.

Tjenesteressurs

Alle dialoger må referere en tjenesteressurs. En tjenesteressurs utgjør autorisasjonsbæreren, og kan sammenlignes med moderne bruk av lenketjenester i Altinn 2. Dette er en beskrivelse av en tjeneste som ligger i Altinn Resource Registry, en ny komponent i Altinn Autorisasjon. Hver tjenesteressurs har en autorisasjonspolicy uttrykt i XACML, som beskriver hvilke tilgangsregler som gjelder for alle dialoger som refererer den. XACML gir stor fleksibilitet i hvor grov- eller finkornet tilgangskontrollen skal være, og Dialogporten vil legge denne policyen til grunn for å bestemme hvem som kan se en gitt dialog, og hvilke handlinger som skal være tilgjengelige.

Eksempelvis vil GUI-handlingen «Signer» referere en action kalt «sign» i XACML-policyen, som krever tilganger den innloggende brukeren ikke besitter. Knappen vil derfor kunne være grået ut og deaktivert. Tjenesteressursen er det tilgangsstyrere i virksomhetene forholder seg til, mht hvem som skal ha tilgang til å gjøre hva på vegne av en virksomhet (tilsvarende dagens tjenestedelegering).

Autorisasjonsattributt

Handlinger og andre deler (f.eks. referanser til dialogelementer) av dialogen kan også oppgi et ekstra autorisasjonsattributt gjennom feltet authorizationAttribute.

Dette muliggjør at man kan ha ulike autorisasjonskrav for samme type handling som er tilgjengelige ved ulike tilstander dialogen har. F.eks. vil det kunne brukes for å la en signeringshandling kun være tilgjengelig for en ekstern revisor/regnskapsfører, mens en annen signeringshandling er tilgjengelig for daglig leder.

Aktivitet

En aktivitet beskriver en eller annen utført handling eller hendelse som har skjedd i tilknytning til dialogen. Hver aktivitet inngår i aktivitetshistorikken, som er en kronologisk liste over aktiviteter. Det er tjenestetilbyder som populerer aktivitetshistorikken etter hvert som ulike tilstandsendringer inntreffer. Dialogporten kan også foreta innslag i aktivitetshistorikken, f.eks. om en dialog blir åpnet for første gang, eller tilgang til dialogen delegeres videre.

Merking (labels)

For å støtte brukerstyrt organisering av dialoger, skal det bygges støtte for å kunne knytter merkelapper (labels) til dialoger. Dette er skriveoperasjoner som finnes kun i sluttbruker-API-et, og påvirker ikke tilstand på selve dialogen.

Begrepsmodell

Under er en forenklet modell som viser relasjonene mellom de ulike begrepene. For en mer overordnet modell av konseptet, se Overordnet modell over konsept.

Overordnet modell over konsept

Under er en overordnet modell som viser relasjonen mellom Dialogporten, tjenesteplattformene som benytter den og sluttbrukere/systemer som konsumerer dialogene som er realisert.

Teknisk ER-diagram

Under er et ER-diagram som viser de konkrete relasjonene mellom de ulike entitetene som er definert. Merk at disse kan ha avvik i navngivning i forhold til modellene og beskrivelsene i dette dokumentet

Systemarkitektur

Dette er den foreløpige systemarkitekturen som ligger til grunn for implementasjonen av Dialogporten.

Autorisasjon

Relasjon til XACML

Hver dialog refererer en tjenesteressurs i Altinn Autorisasjon, som består av en XACML-policy samt metadata som beskriver tjenesten.

Hver action som defineres på en dialog mappes til en tilsvarende “action-id” i XACML. Eksempelvis, gitt følgende action på en dialog som refererer tjenesteressursen min_fine_tjeneste:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
    // ...
    "serviceResource": "min_fine_tjeneste", 
    // ...
    "actions": {
        "gui": [ 
            { 
                "action": "open", // Denne refereres i "Action"-delen  i XACML-policy                
                "title": [ { "code": "nb_NO", "value": "Åpne" } ],
                "url": "https://example.com/some/deep/link/to/dialogs/123456789"
            }
        ]
    }
}

Hvis man ønsker å lage en regel i en policy som gir innehavere av Enhetsregister-rollen DAGL (daglig leder) tilgang til en action open på dialoger som refererer tjenesteressursen med identifikator min_fine_tjeneste, kan dette uttrykkes i XACML som:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<xacml:Rule RuleId="urn:altinn:example:ruleid:1" Effect="Permit">
    <xacml:Target>
        <!-- Subjekt-del -->
        <xacml:AnyOf>
            <xacml:AllOf>
                <xacml:Match MatchId="urn:oasis:names:tc:xacml:3.0:function:string-equal-ignore-case">
                    <xacml:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">DAGL</xacml:AttributeValue>
                    <xacml:AttributeDesignator AttributeId="urn:altinn:rolecode" Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/>
                </xacml:Match>
            </xacml:AllOf>
        </xacml:AnyOf>
        <!-- Ressurs-del -->
        <xacml:AnyOf>
            <xacml:AllOf>
                <xacml:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                    <xacml:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">min_fine_tjeneste</xacml:AttributeValue>
                    <xacml:AttributeDesignator AttributeId="urn:altinn:resource" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/>
                </xacml:Match>
            </xacml:AllOf>
        </xacml:AnyOf>
        <!-- Action-del -->
        <xacml:AnyOf>
            <xacml:AllOf>
                <xacml:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                    <xacml:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">open</xacml:AttributeValue>
                    <xacml:AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/>
                </xacml:Match>
            </xacml:AllOf>
        </xacml:AnyOf>
    </xacml:Target>
</xacml:Rule>

Dette kan uttrykkes i forenklet JSON som:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
    "Rules": [
        {
            "Subjects": [
                "urn:altinn:rolecode:DAGL",
            ],
            "Resources": [
                [
                    "urn:altinn:resource:min_fine_tjeneste"
                ]
            ],
            "Actions": [
                "open"
            ]
        }
}

Autorisasjonsattributter

Autorisasjonsattributter er ytterligere ressurs-attributter som det vil matches mot i en regel i en policy, som kan refereres til i actions og dialogelementer gjennom feltet authorizationAttribute. En slik ressurs er en URN som i eksemplene i dette dokumentet tilhører navnerommet urn:altinn:subresource, men andre navnerom kan også benyttes; f.eks. bruker Altinn Studio vanligvis navnerommet urn:altinn:task.

En action som refererer en subsressurs kan se slik ut:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
    // ...
    "serviceResource": "min_fine_tjeneste", 
    // ...
    "actions": {
        "gui": [ 
            { 
                "action": "sign", // Denne refereres i "Action"-delen  i XACML-policy                
                "authorizationAttribute": "urn:altinn:subresource:autorisasjonsattributt1", // Denne refereres i "Ressurs"-delen  i XACML-policy                
                "title": [ { "code": "nb_NO", "value": "Åpne" } ],
                "url": "https://example.com/some/deep/link/to/dialogs/123456789"
            }
        ]
    }
}

Tilsvarende, for å lage en regel som gir DAGL lov til å utføre handlingen sign på autorisasjonsattributtet urn:altinn:subresource:autorisasjonsattributt1 på dialoger som refererer min_fine_tjeneste:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<xacml:Rule RuleId="urn:altinn:example:ruleid:1" Effect="Permit">
    <xacml:Target>
        <!-- Subjekt-del -->
        <xacml:AnyOf>
            <xacml:AllOf>
                <xacml:Match MatchId="urn:oasis:names:tc:xacml:3.0:function:string-equal-ignore-case">
                    <xacml:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">DAGL</xacml:AttributeValue>
                    <xacml:AttributeDesignator AttributeId="urn:altinn:rolecode" Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/>
                </xacml:Match>
            </xacml:AllOf>
        </xacml:AnyOf>
        <!-- Ressurs-del -->
        <xacml:AnyOf>
            <xacml:AllOf>
                <xacml:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                    <xacml:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">min_fine_tjeneste</xacml:AttributeValue>
                    <xacml:AttributeDesignator AttributeId="urn:altinn:resource" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/>
                </xacml:Match>
                <xacml:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                    <xacml:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">autorisasjonsattributt1</xacml:AttributeValue>
                    <xacml:AttributeDesignator AttributeId="urn:altinn:subresource" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/>
                </xacml:Match>
            </xacml:AllOf>
        </xacml:AnyOf>
        <!-- Action-del -->
        <xacml:AnyOf>
            <xacml:AllOf>
                <xacml:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                    <xacml:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">sign</xacml:AttributeValue>
                    <xacml:AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/>
                </xacml:Match>
            </xacml:AllOf>
        </xacml:AnyOf>
    </xacml:Target>
</xacml:Rule>

Dette kan uttrykkes i forenklet JSON som:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    "Rules": [
        {
            "Subjects": [
                "urn:altinn:rolecode:DAGL",
            ],
            "Resources": [
                [
                    "urn:altinn:resource:min_fine_tjeneste",
                    "urn:altinn:subresource:autorisasjonsattributt1",
                ]
            ],
            "Actions": [
                "sign"
            ]
        }
}

Se issue på Github for eksempler på requests som genereres av Dialogporten.

Bruk av Dialogportens API-er

Tjenesteressursen bestemmer hvilke autorisasjonskontroller som skal legges til grunn for å få tilgang. Typisk innebærer dette at konsumenten innehar en spesiell rolle eller tilhører en spesifikk forhåndsdefinert tilgangsgruppe, eller er blitt delegert tilgang til tjenesteressursen dialogen refererer av en tilgangsstyrer/hovedadministrator hos den aktuelle parten.

For API-konsumenter krever Dialogporten at klienten oppgir et token med et spesifikt scope; digdir:dialogporten. Dette scopet kan for SBS-er/GUI-implementasjoner være tildelt klienten gjennom brukerstyrt datadeling i ID-porten (OAuth2/OIDC) eller ved hjelp av Maskinporten (ren OAuth2). Ved bruk av Maskinporten-token, vil det typisk kreves at det i tillegg autentiseres en systembruker, som innbærer utstedelse av et beriket Maskinporten-token som benyttes mot Dialogporten og/eller tjenestetilbyders API-er. Tjenestetilbydere blir tildelt et eget scope; digdir:dialogporten.serviceprovider som kun er tilgjengelig for Maskinporten-integrasjoner. Dette gir skrivetilgang til Dialogporten og mulighet til å hente ut (og oppdatere) alle dialoger som er opprettet av tjenestetilbyderen. Liste/søke-API-et krever et ytterligere scope; digdir:dialogporten.serviceprovider.search. Tjenestetilbyder kan også konfigurere ytterligere scopekrav for dialoger som egne integrasjoner må inneha for å kunne aksessere dialoger.

Felles arbeidsflate vil av hensyn til brukskvalitet ikke kreve eksplisitt autorisasjon fra sluttbrukeren for tilgang til Dialogporten-API-ene; dette skjer implisitt gjennom innlogging i ID-porten, og Felles arbeidsflate vil bruke et internt scope for å autorisere seg mot Dialogportens API-er.

Bruk av samme token mot både Dialogporten og tjenestetilbyders API

Tjenestetilbyders API-er vil typisk kreve egne scopes som grovkornet autorisasjon. I disse tilfellene vil det kunne utstedes tokens som benyttes mot både Dialogportens API såvel som tjenestetilbyderen, altså scopes for begge API-ene. Dialogporten vil ikke kreve eller verifisere “aud”-claims i tokens, men disse kan benyttes hvis tokenet også skal benyttes mot tjenestetilbyders endepunkter. Klienter må imidlertid vurdere sikkerhetsrisikoen knyttet til at tjenestetilbyder da vil kunne gjenbruke tokenet mot Dialogporten (replay attack). For høyest sikkerhet må klienten hente ut to tokens for bruk mot hhv. Dialogporten API og tjenestetilbyder.

Selvpålagt scopekrav på dialog

Tjenestetilbydere med et stort antall tjenester implementert over ulike systemer kan av sikkerhetshensyn ønske å begrense hver enkelt integrasjons tilgang til Dialogportens privilegerte API-er for å isolere dialoger tilhørende ulike tjenester (eller sikkerhetsdomener) fra hverandre. Ved opprettelse/endring av dialogen, kan et felt i configuration-feltet settes som inneholder en liste over ytterligere Maskinporten-scopes som tjenestetilbyder må ha i oppgitt token for å kunne aksessere den aktuelle dialogen. Dette scopet må også være oppgitt i token ved opprettelse, og ved endring må alle scopes som både i eksisterende og ny liste være oppgitt. På denne måten kan tjenestetilbyder provisjonere ulike Maskinporten-klienter som kan ha tilgang til ulike subsets av dialoger eid av tjenestetilbyderen.

Håndhevelse av autorisasjon hos tjenestetilbyder

Tokens utstedt av Maskinporten vil inneholde en systembruker-id, mens tokens utstedt av ID-porten vil inneholde et fnr/dnr. Det pålegges tjenestetilbyder å håndheve autorisasjon mot egne endepunkter gjennom at det foretas oppslag mot Altinn Autorisasjon hvor man verifiserer tilgangen en gitt systembruker-id eller fnr/dnr har for endepunktet/operasjonen som er forsøkt aksessert/utført. For GUI-endepunkter som aksesserer av sluttbruker gjennom felles arbeidsflate, vil single-sign-on (SSO) i ID-porten sørge for at tjenestetilbyder får autentisert fnr/dnr som står bak requesten og kan foreta autoriasjonsoppslag/håndhevelse som oppleves sømløst for sluttbruker.

Tokens mottatt fra Maskinporten eller ID-porten vil på sikt kunne berikes med finkornede autorisasjonsopplysninger basert på Rich Authorization Requests (RAR) fra SBS-et som Maskinporten/ID-porten verifiserer opp mot Altinn Autorisasjon som foretar en autorisasjonsbeslutning. Hvis tilgang er gitt, populeres tokenet med opplysninger som vil kunne brukes av både Dialogporten og tjenestetilbyder for å håndheve tilgangskontroll uten videre oppslag mot Altinn Autorisasjon (innenfor levetiden av tokenet).

Dialogtoken

For GUI-write actions eller front channel embeds vil det genereres tokens som nettleser/SBS vil kunne bruke mot endepunkter hos tjenestetilbyder. Dette gjør det mulig å foreta forespørsler til sikrede endepunkter uten at sluttbruker må omdirigeres innom ID-porten for SSO, og for tjenesteeier å foreta et ytterligere autorisasjonsoppslag.

Dialogtokenet benyttes som et “bearer token”, altså noe som indikerer at ihendehaveren er autorisert av Dialogporten til en liste med påstander (claims) som ligger i tokenet. Standard JWT-claims og JWS-parametere som definert i RFC7519 og RFC7515 vil inkluderes, i tillegg til de Dialogporten-spesifikke påstandene under:

Dialogporten-spesifikke claims

Claim Beskrivelse Eksempel
c Autentisert som konsument av Dialogporten. Prefikset for hhv. personer (typisk ID-porten), organisasjoner (typisk Maskinporten) eller selvregistrerte brukere. "urn:altinn:person:identifier-no::12018212345, "urn:altinn:organization:identifier-no::991825827" eller "urn:altinn:party-identifier:username::someemail@example.com"
l Sikkerhetsnivå på autentisering (4) 4
u Valgfritt. Hvis det er benyttet et leverandørtoken i Maskinporten, vil autentisert leverandørs organisasjonsnummer oppgis her. "urn:altinn:organization:identifier-no::991825827"
p Hvem konsument opptrer på vegne av (om ikke seg selv), altså hvem som eier det aktuelle dialogen. "urn:altinn:person:identifier-no::12018212345", "ourn:altinn:organization:identifier-no::991825827"" eller "urn:altinn:party-identifier:username::someemail@example.com"
i Unik identifikator til dialog. "e0300961-85fb-4ef2-abff-681d77f9960e"
s Service resource dialogen refererer. "urn:altinn:resource:super-simple-service"
a Autoriserte actions/autorisasjonsattributter "read;write;sign;elementread,urn:altinn:subresource:autorisasjonsattributt1"

Eksempel på dekodet token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "alg": "EdDSA",
  "typ": "JWT",
  "kid" : "dp-2023-01" 
}
// .
{
  "l": 4, // Sikkerhetsnivå
  "c": "urn:altinn:person:identifier-no::12018212345", // Autentisert part
  "p": "urn:altinn:organization:identifier-no::991825827", // Party
  "s": "urn:altinn:organization:identifier-no::825827991", // Supplier (hvis MP-leverandørtoken)
  "i": "e0300961-85fb-4ef2-abff-681d77f9960e", // Dialog-ID
  "a": "read;write;sign;elementread,urn:altinn:subresource:autorisasjonsattributt1",
  "exp": 1672772834,
  "iss": "https://dialogporten.no",
  "nbf": 1672771934,
  "iat": 1672771934 
}
 
// .
// <signatur>

Tokenet kan verifiseres på vanlig vis gjennom at det publiseres et nøkkelsett (JWK) på et kjent endepunkt. Med å hente den offentlige nøkkelen definert av kid kan tjenestetilbyder verifisere at tokenet er gyldig.

Overføring av token til tjenestetilbyder

Tokenet vil inkluderes i responsmodellen som returneres til SBS-er og Felles arbeidsflate i feltet dialogToken. Arbeidsflate vil overføre dette tokenet til statisk frontend (nettleser), hvor front channel embeds eller actions uten navigasjon benytter dette tokenet i en standard Authorization: Bearer <token> HTTP-header gjennom Fetch API.

Endepunktene som aksesseres med dette denne mekanismen må da ha “trust” til Dialogporten som token issuer, og verifisere tokenet (signatur, levetid, claims). De offentlige nøklene som brukes for å verifisere tokenet eksponeres gjennom et well-known-endepunkt med JWK-er. Siden dette foregår via nettleser på fra en annen “origin”, må endepunktene her støtte CORS-protokollen (inkludert pre-flight).

Overføring av token til Dialogporten-API

Dialogporten vil støtte SignalR-basert notififkasjon til sluttbrukersystemer, herunder arbeidsflate, når endringer på dialoger oppstår. SBS-er kan benytte dette i de tilfellene hvor det er behov for å laste dialogen på nytt umiddelbart etter en endring.

Integrasjonsmønster for SBS-er

Under beskrives hvordan SBS-er foretar autentisering for å kunne autoriseres i både Dialogporten og hos tjenestetilbyders API-er.

Ting som legges til grunn / avgrensninger

  • Det finnes en systembruker-mekanisme som en beskrankningsmekanisme for virksomheter
  • Hvem som “eier” denne, eller hvordan den provisjoneres er out-of-scope.
  • Det opereres med tre nivåer av autorisasjon
    • Scope-nivå
      • I Dialogporten er denne grovkornet (f.eks. digdir:dialogporten eller altinn:instances.read), og autoriserer kun for å kunne kalle API-et. Gir i seg selv ikke tilgang til noen tjenester.
      • Scopes tolkes typisk mer finkornet hos tjenestetilbyder, som gjerne har scopes per tjeneste (f.eks. skatteetaten:summertskattegrunnlag).
    • Tjenestenivå
      • Har tilgang til en eller flere actions på en tjeneste og/eller definert autorisasjonsattributt (egen ressurs-attributt i XACML, tradisjonelt “prosessteg” i Altinn2) av tjeneste
    • Dialognivå
      • Tilgang til konkret instans, aka “instansdelegering”.
      • Tilgang på tjenestenivå gir tilgang til alle dialoger, men noen kan ha tilgang til en eller flere actions til enkelte dialoger og/eller tilhørende definerte autorisasjonsattributter.
  • Det tas utgangspunkt i ikke-interaktive, virksomhetsautentiserte flyter med Maskinporten som IDP. Det er derfor fem prinsipielle aktører; sluttbrukersystemet, Dialogporten, Maskinporten, Altinn Autorisasjon og Tjenestetilbyders API for tjenesten, samt Altinn Token Exchange + Altinn Registry for håndtering av systembrukere.
  • Varianter med ID-porten vil kunne fungere annerledes (f.eks. faller Token Exchange ut, siden man umiddelbart har en “bruker”), avhengig av grad av interaktivitet. Disse er ikke tegnet inn i denne omgang.
  • Bruk av flere tokens eller aud-claim forutsettes for å unngå problematikk rundt replay-angrep.

Maskinporten-token med systembruker-ID

Maskinporten foretar autentisering av systembruker/passord og utsteder et beriket token med identifikator for systembrukeren. Både tjenestetilbyder og Dialogporten må foreta oppslag mot Altinn Autorisasjon for å autorisere den oppgitte systembrukeren på tjenestenivå.

Maskinporten-token med innbakt autorisasjon

I dette mønsteret oppgir SBS systembruker + passord, samt tjenesteressurs i forespørselen til Maskinporten, som da foretar både grov- og finkornet autorisasjon. Dette krever innføring av RAR (Rich Authorization Requests) for Maskinporten, og en tettere kobling mellom Maskinporten og Altinn Autorisasjon. Samme token-type kan benyttes mot både Tjenestetilbyder og Dialogporten, men aud-claim må settes i token og valideres for å unngå å åpne for replay-attacks.

Integrasjon med event-komponent

Dialogporten vil generere events automatisk basert på endringer som gjøres på dialog-entiteten. Det vil også gjøres genereres events for hvert separate innslag i aktivitetshistorikken samt dialoglementer. Se

Se case-01 for eksempler på hvordan events genereres.

Knyttet til dialog-entiteten

Opprettelse/endring/sletting av dialog-entiteten genererer meldinger med følgende typer:

Type Når
dialogporten.dialog.created.v1 Dialogen opprettes
dialogporten.dialog.updated.v1 Tilstand på dialogen er endret
dialogporten.dialog.deleted.v1 Dialogen slettes

I tillegg genereres det en event med type dialogporten.dialog.seen.v1 når dialogen lastes for første gang etter at den er oppdatert (altså seenDateTime < max(updatedDateTime, createdDateTime). Denne eventen genereres for hver enkelt sluttbruker som har lastet dialogen.

Eksempel på event ved opprettelse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    "specversion": "1.0",

    // Unik event-id
    "id": "91f2388f-bd8c-4647-8684-fd9f68af5b15",
    
    // Se "Type" i tabell over for liste over mulige hendelser
    "type": "dialogporten.dialog.created.v1",
    
    // Timestamp for når hendelsen inntraff i Dialogporten
    "time": "2023-02-20T08:00:06.4014168Z",
    
    // urn:altinn:resource:{serviceResource}
    "resource": "urn:altinn:resource:super-simple-service", 
    
    // Dialog-ID
    "resourceinstance": "f4e6df3c-7434-44c3-875e-8dca1cdf0b20",
    
    // Party
    "subject": "urn:altinn:organization:identifier-no::991825827", 
    
    // URL til dialog i Dialogporten. Merk denne vil gi 410 Gone hvis type er `dialogporten.dialog.deleted.v1`
    "source": "https://dialogporten.no/api/v1/enduser/dialogs/f4e6df3c-7434-44c3-875e-8dca1cdf0b20" 
}

Eksempel på event ved endring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    "specversion": "1.0",

    // Unik event-id
    "id": "91f2388f-bd8c-4647-8684-fd9f68af5b15",
    
    // Se "Type" i tabell over for liste over mulige hendelser
    "type": "dialogporten.dialog.updated.v1",
    
    // Timestamp for når hendelsen inntraff i Dialogporten
    "time": "2023-02-20T08:00:06.4014168Z",
    
    // urn:altinn:resource:{serviceResource}
    "resource": "urn:altinn:resource:super-simple-service", 
    
    // Dialog-ID
    "resourceinstance": "f4e6df3c-7434-44c3-875e-8dca1cdf0b20",
    
    // Party
    "subject": "urn:altinn:organization:identifier-no::991825827", 
    
    // URL til dialog i Dialogporten. Merk denne vil gi 410 Gone hvis type er `dialogporten.dialog.deleted.v1`
    "source": "https://dialogporten.no/api/v1/enduser/dialogs/f4e6df3c-7434-44c3-875e-8dca1cdf0b20"
}

Knyttet til dialogelementer

Hvis det gjøres endringer i listen av dialogelementer, skal dette føre til at det produseres egne events for dette som indikerer hva som har skjedd. source vil referere selve dialogelementet (ikke dialogen).

Eventer har type som er prefikset/navnerommet dialogporten.dialog.element. Under er en tabell som spesifiserer typene:

Type Når
dialogporten.dialog.element.created.v1 Tjenestetilbyder har lagt til et dialogelement
dialogporten.dialog.element.updated.v1 Tjenestetilbyder har modifisert et dialogelement
dialogporten.dialog.element.deleted.v1 Tjenestetilybder har slettet et dialogelement

Eksempel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
    "specversion": "1.0",

    // Unik event-id
    "id": "7b358c4f-4073-41f0-a39d-a1fac90b630b",
    
    // Se "Type" i tabell over for liste over mulige hendelser
    "type": "dialogporten.dialog.element.created.v1",
    
    // Timestamp for når hendelsen inntraff i Dialogporten
    "time": "2023-02-20T08:00:06.4014168Z",
    
    // urn:altinn:resource:{serviceResource}
    "resource": "urn:altinn:resource:super-simple-service", 
    
    // Dialog-ID
    "resourceinstance": "b8643c00-c826-41c7-8758-bfc0ca5c19fa",
    
    // Party
    "subject": "urn:altinn:organization:identifier-no::991825827",

    // URL til dialogelementet i Dialogporten
    "source": "https://dialogporten.no/api/v1/enduser/dialogs/b8643c00-c826-41c7-8758-bfc0ca5c19fa/elements/da506c38-b19f-45d4-963e-927df959a5f8",
    
    // Disse hentes verbatim fra dialogelementet. Kun "dialogElementId" er alltid oppgitt, alle andre felter
    // vil kunne være utelatt siden de er valgfrie
    "data": { 
        "dialogElementId": "da506c38-b19f-45d4-963e-927df959a5f8",
        "relatedDialogElementId": "cfdd19a4-8cf9-4138-9930-36478fdce398",
        "dialogElementType": "skd:form-type-1"
    }
} 

Knyttet til aktivitetshistorikken

Det vil alltid bli generert egne events for hvert nye innslag i aktivitetshistorikken. source vil referere selve innslaget (ikke dialogen). Det vil også inkluderes en data som inneholder ytterligere informasjon som i mange tilfeller lar systemer kunne agere direkte mot tjenesteeiers API-er uten å måtte hente dialog/aktivitet først.

Eventer har type som er prefikset/navnerommet dialogporten.dialog.activity. Suffikset er gjenspeiler mulige verdier av activityType.

Type Når
dialogporten.dialog.activity.submission.v1 Tjenestetilbyder har lagt til en aktivitet av type submission
dialogporten.dialog.activity.feedback.v1 Tjenestetilbyder har lagt til en aktivitet av type feedback
dialogporten.dialog.activity.information.v1 Tjenestetilbyder har lagt til en aktivitet av type information
dialogporten.dialog.activity.error.v1 Tjenestetilbyder har lagt til en aktivitet av type error
dialogporten.dialog.activity.closed.v1 Tjenestetilbyder har lagt til en aktivitet av type closed
dialogporten.dialog.activity.seen.v1 Dialogen åpnes/lastes for første gang (etter en feedback-aktivitet)
dialogporten.dialog.activity.forwarded.v1 Dialogen er videresendt/delegert til noen andre.

Eksempel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
    "specversion": "1.0",

    // Unik event-id
    "id": "91f2388f-bd8c-4647-8684-fd9f68af5b15",
    
    // Se "Type" i tabell over for liste over mulige hendelser
    "type": "dialogporten.dialog.activity.submission.v1",
    
    // Timestamp for når hendelsen inntraff i Dialogporten
    "time": "2023-02-20T08:00:06.4014168Z",
    
    // urn:altinn:resource:{serviceResource}
    "resource": "urn:altinn:resource:super-simple-service", 
    
    // Dialog-ID
    "resourceinstance": "f4e6df3c-7434-44c3-875e-8dca1cdf0b20",
    
    // Party
    "subject": "urn:altinn:organization:identifier-no::991825827",

    // URL til aktivitetshistorikk-innslag i Dialogporten
    "source": "https://dialogporten.no/api/v1/enduser/dialogs/f4e6df3c-7434-44c3-875e-8dca1cdf0b20/activityhistory/21241c7e-819f-462b-b8a4-d5d32352311a",
    
    // Disse hentes verbatim fra aktivitetshistorikk-innslaget. Kun "activityId" er alltid oppgitt, alle andre felter
    // vil kunne være utelatt siden de er valgfrie i activityHistory
    "data": { 
        "activityId": "21241c7e-819f-462b-b8a4-d5d32352311a",
        "relatedActivityId": "cfdd19a4-8cf9-4138-9930-36478fdce398",
        "extendedActivityType": "additional-info-received",
        "dialogElementId": "54ae8387-7320-4693-8423-0ceb0efaf5fa"
    }
} 

Autorisasjon knyttet til produsering/konsumering av events

Tilgang til events reguleres også av den samme autoriasjonspolicyen for tjenestressursen som dialogene benytter, gitt gjennom resource. Dialogporten har imidlertid en privilgert tilgang til eventkomponenten som gjør at den kan generere events for alle tjenesteressurser, som da innebærer at det ikke behøves å opprettes egne regler i policyen for Dialogporten.

For alle andre konsumenter reguleres konsum (herunder opprettelse av abonnement) av actionen subscribe. Hvis tjenesteeier (eller andre parter) skal kunne produsere vilkårlige events, må det opprettes regler med action publish. Les mer om dette i dokumentasjonen for event-komponenten.

Et eksempel:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{
    "Rules": [
        // Gir ID-porten-autentiserte personer med DAGL hos party og Maskinporten-autentiserte 912345678 tilgang 
        // til å konsumere events av type "dialogporten.dialog.activity.submission.v1" for ressursen
        // "urn:altinn:resource:super-simple-service"
        {
            "Subjects": [
                "urn:altinn:rolecode:DAGL",
                "urn:altinn:organizationnumber:912345678",
            ],
            "Resources": [
                [
                    "urn:altinn:resource:super-simple-service",

                    // Regler kan også begrenses på event-type
                    "urn:altinn:eventtype:dialogporten.dialog.activity.submission.v1",
                ]
            ],
            "Actions": [
                "subscribe"
            ]
        },
        // Gir Maskinporten-autentiserte 912345678 tilgang til å produsere hvilken som helst event-type for ressursen
        // "urn:altinn:resource:super-simple-service"
        {
            "Subjects": [
                "urn:altinn:organizationnumber:912345678",
            ],
            "Resources": [
                [
                    "urn:altinn:resource:super-simple-service",
                ]
            ],
            "Actions": [
                "publish"
            ]
        }
}

Les mer om Event-komponenten på Altinn Docs.

Sekvensbeskrivelser

Under følger punktvis beskrivelser av fire ulike sekvenser. Det er to måter en dialog kan initieres på; enten av sluttbruker eller tjenestetilbyder. Hver av disse kan gjennomføres ved hjelp av GUI eller API.

Tjenestetilbyder-initiert dialog

Opprettelse av dialog

Sekvensdiagram

Tekstlig beskrivelse av trinn

  1. Tjenestetilbyder oppretter tjenesteressurs i Altinn Resource Registry som refererer den aktuelle tjenesten
  2. Tjenestetilbyder oppretter dialog som
    • Referer tjenesteressurs
    • Inneholder tekstlig metadata (tittel, ingress etc) i flere språk
    • Inneholder andre (valgfrie) metadata som f.eks.
    • Frist
    • “Fra”-felt
    • Dato for når dialogen skal aktiveres
    • Eventuell tilhørlighet til dialog-gruppe
    • Inneholder (valgfri) URI for å hente oppdatering strukturert versjon av dialogen, hvis hensiktsmessig for tjenesten. Brukes typisk i det brukeren ekspanderer/åpner en grafisk fremvisning av dialogen for å vise
      • Hvilke handlinger som kan utføres på dialogen (se under)
      • Hvis ikke oppgitt, vises de metadata/handlinger jf. siste oppdatering som ble gjort av tjenestetilbyder (hvis noen, etter opprettelse)
    • Beskriver tilgjengelige handlinger (for både API og GUI)
      • Strukturert liste over handlinger som kan gjøres på dialogen, typisk “Åpne”, “Arkiver”, “Slett”, “Bekreft”, “Signer”, “Betal”, “Les mer”, etc.
      • GUI-handlinger kan flagges som primær, sekundær og tertiær-handlinger som påvirker hvordan dette vises til bruker (f.eks. kan primær og sekundærhandlinger vises som ulike typer knapper, mens tertiærhandlinger vises i en nedtrekksliste/tekstlenker).
      • Er gjenstand for autorisasjon definert av referert tjenesteressurs og eventuelt autorisasjonsattributt. F.eks. vil f.eks. “Signer” kunne kreve andre rettigheter avhengig av policy knyttet til tjenesteressursen.
      • Hver GUI-handling inneholder
        • En identifikator for handlingen. “Standard”-handlinger vil kunne oppgis som allerede finnes oversatt i Dialogporten.
        • Hvis ikke standard-handling, tekst som beskriver handlingen i flere språk
        • En valgfri hjelpetekst som kan fremvises brukeren som gir mer informasjon om hva handlingen innebærer
        • Flagg som indikerer om handlingen er en skriveoperasjon
        • En URI som enten (1) brukeren vil omdirigert til når hen aktiverer det aktuelle GUI-dialogen (f.eks. en knapp) eller (2) sluttbrukersystemet (i kontekst av arbeidsflate, brukerens nettleser) kaller med POST/DELETE
        • Flagg som indikerer om dialogen skal slettes/arkiveres i Dialogporten hvis kall til URI lykkes (vil brukes til f.eks. “Er du sikker”-prompts)
      • Hver API-handling inneholder
        • En identifikator for handlingen
        • Hvilken http-metode som skal benyttes
        • En URI som handlingen skal utføres mot
        • JSON Schema el.l. som beskriver datamodellen som skal pushes/pulles
    • Inneholder valgfri liste over dialogelementer, som består av
      • En identifikator som kan være oppgitt av tjenesteeier
      • Indikator på hva slags tjenestespesifikk type dialogelement er
      • Indikator på om dialogelementet er tiltenkt API eller GUI-kanaler
      • URL til dialogelementet hvor det kan hentes (GET) evt omdirigeres til
    • Kan muteres etter opprettelse
      • Tilgjengelige handlinger kan oppdateres når som helst av tjenestetilbyder
      • Tittel og annen tekstlig metadata
      • Status (“under utfylling”, “klar til signering”, “venter på andre”, “venter på svar fra tjenestetilbyder” etc)
    • Etter vellykket opprettelse, returners en unik identifikator for dialogen (identifikator kan også opprettes av tjenestetilbyder).
  3. Når dialogen er opprettet/endret vil det
    • Genereres hendelser som vil kunne konsumeres av parten
    • Disse kan igjen være koblet til brukerstyrt varsling på e-post/SMS andre push-kanaler

Konsum gjennom GUI (portal)

I beskrivelsene under brukes Felles Arbeidsflate som eksempel på en implementasjon av Dialogporten-API, men tilsvarende sekvenser kan også gjelde for andre GUI-klienter.

Sekvensdiagram

Tekstlig beskrivelse av trinn

  1. Bruker mottar varsling på en eller annen kanal, og logger inn i Felles Arbeidsflate
  2. Dialogen har en grafisk fremstilling som viser overskrift, status og andre metadata
  3. Bruker klikker på dialogen for å ekspandere den. Ekspandert dialog viser rikt innhold som tjenestetilbyder har definert, sammen med tilgjengelige handlinger. Hvis oppdatering feilet, vises enten feilmelding som tjenestetilbyder oppga, eller en standardfeilmelding.
  4. Bruker klikker på den definerte primærhandlingen.
    • Felles Arbeidsflate vil da redirecte brukeren (nettleseren) til oppgitt URI.
    • Hvis ikke sesjon foreligger hos tjenestetilbyder, redirectes bruker innom ID-porten som pga. SSO umiddelbart vil redirecte bruker tilbake. Tjenestetilbyder vil da ha autentisert fnr/dnr
  5. Tjenestetilbyder identifiserer {handling, part, tjenesteressurs} eller {handling, dialog-id} utfra URL som er forsøkt aksessert, og foretar en autorisasjonsforespørsel til Altinn Autorisasjon.
  6. Ved positiv autorisasjonbeslutning blir brukeren logget inn hos tjenestetilbyder og tatt inn til dialogen hos tjenestetilbyder, hvor brukeren interagerer med tjenesten. Etter hvert som dialogen skrider frem, kan tjenestetilbyder gjøre asynkrone bakkanal-kall til Dialogporten for å oppdatere dialogen slik den fremstår for brukeren.
  7. Hvis brukeren fullfører dialogen, kan tjenestetilby,der gjøre et bakkanal-kall for å indikere til Dialogporten at dialogen skal markeres som fullført. Dialoget blir da merket som fullført, og vil typisk flyttes til “arkiv”-visning i Felles arbeidsflate. Merk at det fremdeles kun ligger metadata på dialogen i Dialogporten.
  8. Når brukeren senere ekspanderer dialogen i en arkiv-visning i Felles Arbeidsflate, vises da de data som siste ble lagt inn på dialogen av tjenestetilbyder. Typisk vises da bare en kort tekst og et vedlegg til en PDF-versjon av en kvittering/gjenpart el.l. som ligger hos tjenestetilbyder.

Konsum gjennom API

Sekvensdiagram

Tekstlig beskrivelse av trinn

  1. SBS abonnerer på hendelser knyttet til opprettelse av dialoger av en eller flere typer for en gitt part, og mottar en notifikasjon om at en ny dialog er opprettet. Notifikasjonen inneholder en URI til dialogen i Dialogportens API. Alternativt kan liste med dialoger hentes/søkes opp gjennom standard Dialogporten-API-er.
  2. Avhengig av autorisasjonspolicy tilhørende tjenesteressursen, autoriserer SBS-et seg. Les mer i avsnittet Autorisasjon.
  3. Ved uthenting av dialogen som ble referert av hendelsen, returneres en strukturert modell som langt på vei speiler modellen som tjenestetilbyder opprinnelig sendte inn (typisk har samme identifikator). Listen over handlinger definerer da hva SBS-et kan foreta seg, og hvilke endepunkter som må aksesseres for å utføre handlingene.  Enkelte handlinger kan være synlige/gyldige kun for portal, eller kun for API.  Handlinger kun synlige for API kan også referere JSON schemas el.l. som beskriver datamodellen som forventes på det aktuelle endepunktet.
  4. SBS-et interagerer med tjenestetilbyders API gjennom endepunktene som dialogen beskriver, og/eller i tråd med swagger/annen dokumentasjon som tjenestetilbyder har tilgjengeliggjort f.eks. via API-katalogen. Tjenestetilbyder foretar autorisasjonsoppslag mot Altinn Autorisasjon. Etter hvert som dialogen skrider frem, kan tjenestetilbyder gjøre asynkrone bakkanal-kall til Dialogporten for å oppdatere dialogen slik den fremstår for brukeren både i portal og API.

Sluttbruker-initiert dialog

Gjennom GUI (portal)

Sekvensdiagram

Tekstlig beskrivelse av trinn

  1. Bruker oppdager tjeneste gjennom tjenestekatalog, søkemotor, etatenes nettsider el.l.
  2. Bruker starter tjenesten og blir umiddelbart tatt inn i brukerflaten hos tjenestetilbyderen, og velger aktør avhengig av tjenestens natur (via autorisasjonskall mot Altinn Autorisasjon for å bygge aktørliste)
  3. Tjenestetilbyder gjør bakkanal-kall for å opprette dialog i Dialogporten
  4. Sluttbruker interagerer med tjenesten, og tjenestetilbyder gjør kall til Dialogporten for å oppdatere dialogen.
  5. Hvis bruker avslutter økten før dialogen er ferdigstilt, kan han/hun (eller andre autoriserte) fortsette å jobbe med dialogen gjennom å aksessere dialogen i Felles Arbeidsflate. Prosessen blir da som “tjenestetilbyder-initiert dialog / Konsum gjennom GUI (portal)” steg 2. 

Gjennom API

  • Her er det to nærliggende alternativer - skal tjenester kunne “instansieres” a) gjennom et felles “instansierings”-API i Dialogporten som gjør bakkanal-kall til tjenestetilbyder og returnerer en dialog med liste over handlinger/endepunkter? b) direkte mot tjenestetilbyders API-er som da kan gjøre bakkanal-kall til Dialogporten for å opprette dialogen?

  • Begge deler bør kanskje kunne støttes? Førstnevnte gir en mer homogen løsning sett fra SBS-ene sin side; selv om all kommunikasjon går direkte mot tjenestetilbyder etter instansiering, er dialogen i Dialogporten den som vil kunne reflektere gjeldende tilstand/status og aktuelle handlinger. Det andre løsningen gir en løsere kobling til Dialogporten, men gjør at SBS-et i mindre grad kan forholde seg til en felles brukerflate.
  • I alle tilfeller skal Dialogporten støtte at tjenesteeier oppgir identifikator for dialogen.

Variant med instansierings-API

  1. (“Design-time”) SBS oppdager API gjennom API-katalog eller annen dokumentasjon, og foretar merkantil og teknisk onboarding (setter opp Maskinporten-klient med rette scopes, oppretter systembruker etc)
  2. SBS autentiserer seg (tilsvarende “tjenestetilbyder-initiert dialog / Konsum gjennom API”, trinn 2.
  3. SBS gjør et kall til et standard API i Dialogporten (“createinstance” el.l) som oppgir aktør og tjenesteressurs
  4. Dialogporten foretar autorisasjon basert på policy knyttet til tjenesteressurs, og hvis godkjent gjør et bakkanal kall til et instansierings-endepunkt som er definert på tjenesteressurs. Kallet inneholder en standard modell som beskriver autentisert part, valgt aktør, og tjenesteressurs.
  5. Tjenestetilbyder oppretter instans (el.l) i egne systemer, og gjør kall tilbake til Dialogporten i ny kanal for å opprette dialog som beskrevet i “tjenestetilbyder-initert dialog / opprettelse av dialog”, trinn 2.
  6. Tjenestetilbyder mottar fra Dialogporten bekreftelse på at dialogen er opprettet
  7. Tjenestetilbyder returnerer identifikator til dialog til Dialogporten i tråd som startet i trinn 3
  8. Dialogporten laster den nyopprettede dialogen, og returner dette til SBS
  9. SBS interagerer med tjenestetilbyders API-er som beskrevet i “tjenestetilbyder-initiert dialog / Konsum gjennom API”, trinn 4

Variant uten instansierings-API

  1. SBS autentiserer/autoriserer seg mot Maskinporten/ID-porten og får ut access tokens med nødvendige scopes
  2. SBS gjør et eller annet kall for å initiere (og potensielt samtidig fullføre) en dialogtjeneste hos tjenestetilbyder
  3. Tjenestetilbyder foretar et oppslag mot Altinn Autorisasjon for å sjekke om forespørselen (fnr/systembruker) er autorisert for den aktuelle tjenesteressursen
  4. Tjenestetilbyder oppretter dialogen i egne systemer, og returnerer en referanse til SBS-et
  5. SBS-et kan ved behov gjøre et oppslag for å hente prefill-data, hvis ikke dette er inkludert i responsen på forrige trinn
  6. SBS-et foretar en innsending basert på hva sluttbrukeren oppgir
  7. Tjenestetilbyderen validerer innsendingen
  8. Tjenestetilbyder returner OK til SBS-et. Parallelt (asynkront) opprettes dialog i Dialogporten, og tjenesteeier oppgir å bruke samme identifikator for dialogen.
  9. På et senere tidspunkt kan SBS-er jobbe videre med dialogen gjennom dialogen i Dialogporten, eller fortsette å benytte API-ene til tjenestetilbuder direkte.

Implementasjon / Proof-of-concept

En foreløpig implementasjon er publisert, se https://dppoc-webapi.azurewebsites.net/swagger/. Git-repository er åpent tilgjengelig, og ligger på Github.

OpenAPI

En OpenAPI 3.0.1 specification (OAS) basert på modellene beskrevet under kan sees på https://dppoc-webapi.azurewebsites.net/swagger/V0.1/swagger.json.

Eksempel-modeller

Under er utkast til JSON-modeller slik de kan fremstå i API-ene som må implementeres gitt beskrivelsene over, med kommentarer.

dialog-create-request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
// Input modell som tjenesteeiere oppgir for å opprette en dialog.
// Modellen kan også oppdateres/muteres med PATCH-kall (se https://jsonpatch.com/)
//Ikke-komplekse felter som ligger på rotnivå kan ikke endres (med unntak av "status").

// POST /dialogporten/api/v1/servicowner/dialogs
{
    // Tjenestetilbyder kan valgfritt oppgi en egen-generert UUID her. Hvis det ikke oppgis vil Dialogporten generere
    // en unik identifikator som blir returnert ved opprettelse
    "id": "e0300961-85fb-4ef2-abff-681d77f9960e",

    // Identifikator som refererer en tjenesteressurs ("Altinn Service Resource") i Altinn Autorisasjon
    // Se https://docs.altinn.studio/authorization/modules/resourceregistry/
    // Dette bestemmer også hvilken autorisasjonspolicy som legges til grunn.
    "serviceResource": "urn:altinn:resource:super-simple-service", 

    // Organisasjonsnummer, fødselsnummer eller brukernavn (aka "avgiver" eller "aktør") - altså hvem sin dialogboks 
    // skal dialogen tilhøre. Brukernavn benyttes for selv-registrerte bruker, og er typisk en e-postadresse.
    "party": "urn:altinn:organization:identifier-no::991825827", 
                                  
    // Vilkårlig referanse som presenteres sluttbruker i UI. Dialogporten tilegger denne ingen semantikk (trenger f.eks. ikke
    // være unik). Merk at identifikator/primærnøkkel vil kunne være den samme gjennom at tjenestetilbyder kan oppgi "id",
    // så dette kan f.eks. brukes for et saksnummer eller en annen referanse hos party eller en tredjepart (systemleverandør). 
    "externalReference": "123456789",

    // Alle dialoger som har samme prosess-id vil kunne grupperes eller på annet vis samles i GUI    
    "process": {
        "id": "some-arbitrary-id",
        
        // Bestemmer rekkefølgen denne dialogen har blant alle dialoger som har samme prosess-id
        "order": 1,
        
        // Trenger bare oppgis av én dialog. Hvis oppgitt av flere, er det den med høyest "order"-verdi 
        // som skal benyttes.
        "name": [ { "code": "nb_NO", "value": "Navn på prosess." } ]
    },

    // Kjente aggregerte statuser som bestemmer hvordan dialogen vises for bruker: 
    // "unspecified"    = Dialogen har ingen spesiell status. Brukes typisk for enkle meldinger som ikke krever noe 
    //                    interaksjon. Dette er default. 
    // "in-progress"    = Under arbeid. Generell status som brukes for dialogtjenester der ytterligere bruker-input er 
    //                    forventet.
    // "waiting"        = Venter på tilbakemelding fra tjenesteeier
    // "signing"        = Dialogen er i en tilstand hvor den venter på signering. Typisk siste steg etter at all  
    //                    utfylling er gjennomført og validert. 
    // "cancelled"      = Dialogen ble avbrutt. Dette gjør at dialogen typisk fjernes fra normale GUI-visninger.
    // "completed"      = Dialigen ble fullført. Dette gjør at dialogen typisk flyttes til et GUI-arkiv eller lignende.
    "status": "in-progress", 
    
    // En vilkårlig streng som er tjenestespesifikk
    "extendedStatus": "SKE-ABC",
    "dates": {
        // Hvis oppgitt blir dialogen satt med en frist 
        // (i Altinn2 er denne bare retningsgivende og har ingen effekt, skal dette fortsette?)
        "dueDateTime": "2022-12-01T12:00:00.000Z",
        
        // Mulighet for å skjule/deaktivere en dialog på et eller annet tidspunkt?
        "expiryDate": "2023-12-01T12:00:00.000Z" 
    },
    
    // Alle tekster som vises verbatim må oppgis som en array av oversatte tekster. 
    // Det som benyttes er brukerens valgte språk i Dialogboksen
    "content": [
        {
            "type": "Title",
            "value": [{ "code": "nb_NO", "value": "En eksempel på en tittel" } ]
        },
        {
            "type": "Summary",
            "value": [{ "code": "nb_NO", "value": "Kort tekst for oppsummering" } ]
        },
        {
            "type": "AdditionalInfo",
            "value": [{ "code": "nb_NO", "value": "Ytterligere informasjon med <em>begrenset</em> HTML-støtte.
                Dette innholdet vises kun i detaljvisning av dialogen." } ]
        },
        {
            "type": "SenderName",
            "value": [{ "code": "nb_NO", "value": "Overstyrt avsendernavn (bruker default tjenesteeiers navn)" } ]
        }
    ],

    // Search Tags gjør det mulig å oppgi ord og fraser som det skal kunne søkes på, men som en ikke ønsker å
    // eksponere i DTO-en til sluttbrukere
    "searchTags": [
        {
            "value": "noe søkbart"
        }
    ],

    // Dialogelementer kan være tiltenkt enten GUI eller API, eller begge. GUI-dialogelementer er typiske filvedlegg i 
    // menneskelesbart format, f.eks. PDF, som tjenestetilbyder legger ved dialogen. Dette kan være utsendinger fra 
    // tjenestilbyder eller innsendinger fra parten. API-dialogelementer er strukturerte filer tiltenkt SBS-er. 
    // Dette kan være enkelteskjemaer, egne prefill-modeller, strukturerte feilmeldinger,tidligere innsendte skjema etc.
    //
    // Dialogelementer kan også indikeres at de skal embeddes, altså lastes og vises direkte i det aktuelle 
    // sluttbrukersystemet (arbeidsflate/nettleser). Denne typer dialogelementer har typisk mimeType: text/markdown
    // 
    // Dialogelementer kan hentes (leses) gjennom oppgitt URL. Actions kan peke på et spesifikt dialogelement for andre
    // operasjoner direkte knyttet til et dialogelement.
    "dialogElements": [
        {
            // Unik identifikator for dialogElement. Kan oppgis av tjenestetilbyder for å sikre idempotens.
            "dialogElementId": "5b5446a7-9b65-4faf-8888-5a5802ce7de7",

            // Hvis dialogelementet har en relasjon til et annet dialogelement, f.eks. en tidligere innsending, kan dette 
            // oppgis her. 
            "relatedDialogElementId": "dbce996a-cc67-4cb2-ad2f-df61cee6683a",
            
            // Vilkårlig URI som indikerer type dialogElement
            "dialogElementType": "skd:form-type-1",   

            // Valgfri: Brukes for å vise sluttbrukeren hva dette er, typisk bare brukt i GUI
            "displayName": [ { "code": "nb_NO", "value": "Innsendt skjema" } ],
            
            // Valgfri: Det kan oppgis en referanse til det som mappes til en XACML-ressurs-attributt. Hvis oppgitt, må 
            // brukeren må ha tilgang  til actionen "elementread" i XACML-policy evt. begrenset til denne ressursen. 
            // Hvis ikke oppgitt kreves bare "read".
            "authorizationAttribute": "urn:altinn:subresource:somesubresource",
            "urls": [
                {
                    // Indikerer hvilken type konsument denne URL-en er tiltenkt (menneske/GUI eller maskin/API)
                    "consumerType": "gui",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/5b5446a7.pdf",
                    // Valgfri: MIME-type. Brukes i GUI for hint om hva slags dokument dette er 
                    "mimeType": "application/pdf"
                },
                {
                    "consumerType": "api",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/5b5446a7.xml",
                    "mimeType": "application/json"
                }
            ]
        },
        {
            // Dialogelementer kan også representere innhold som skal lastes og embeddes i GUI
            "authorizationAttribute": "urn:altinn:subresource:somesubresource",
            // Valgfri: Blir rendret som en tittel for det embedda innholdet.
            "displayName": [ { "code": "nb_NO", "value": "Melding om bla bla bla" } ],
            "urls": [
                {
                    "consumerType": "gui",
                    // Kan bare brukes på "gui" actions. Sluttbrukersystemet (statisk del i nettleseren) vil laste 
                    // denne med Fetch API og oppgi dialogtoken, og vise dette direkte i detaljvisning.
                    // Det kan være flere front-channel embeds, enten innenfor et og samme dialogelement eller på
                    // tvers av flere dialogelementer. Innenfor samme dialogelement vil statisk del av arbeidsflate 
                    // typisk rendre disse etter hverandre med en eller annen visuell separator. 
                    //
                    // Hvis flere dialogelementer inneholder frontChannelEmbeds, vil GUI måtte bestemme
                    // hvem av disse som er relevant å vise. En mulig logikk her vil være å vise den som er referert 
                    // til av det nyeste aktivitetshistorikk-innslaget, og vise evt. øvrige kollapset (kan lene seg
                    // på "displayName"). Hvis ingen er referert til av aktivitetshistorikk-innslag, vis kun den siste
                    // i lista.
                    "frontChannelEmbed": true,
                    // Hvis frontChannelEmbed er oppgitt, må også contentType oppgis. Her støttes i første omggang
                    // kun "text/markdown", men her kan det tenkes at andre mimeTypes (f.eks. video) kan håndteres 
                    // på andre måter i fremtiden, eller at man støtter andre strukturerte formater som rendres
                    // på en spesifikk måte
                    "url": "https://example.com/api/dialogs/123456789/user-instructions"
                }
            ]
        } 
    ],
    "actions": {
        "gui": [ 
            { 
                "action": "open", // Denne kan refereres i XACML-policy                
                "priority": "primary", // Dette bestemmer hvordan handlingen presenteres.
                "title": [ { "code": "nb_NO", "value": "Åpne i dialogtjeneste" } ],
                "url": "https://example.com/some/deep/link/to/dialogs/123456789"
            },
            {
                "action": "confirm",
                // Det kan oppgis en valgfri referanse til en XACML-ressurs-attributt
                "authorizationAttribute": "urn:altinn:subresource:somesubresource", 
                "priority": "secondary",
                "title": [ { "code": "nb_NO", "value": "Bekreft mottatt" } ],

                // Dette indikerer til GUI at dette er en eller annen skrivehandling som ikke skal innebære
                // en omdirigering av nettleseren, men kun foreta en POST/DELETE med Fetch API-et med dialogtoken.
                "writeAction": {
                    // enum: post, delete (valgfritt, default: post)
                    // Indikerer hvilket verb som skal benyttes i requesten
                    "method": "post",
                
                    // Arbeidsflate og andre SBS-er står fritt til å definere hva som skal skje avhengig av hva responsen
                    // til dette endepunktet viser. Arbeidsflate vil i utgangspunktet basere seg på at SignalR-basert
                    // notifikasjon mottas etter at tjenesteeier har oppdatert elementet i bakkanal, slik at dette da kan
                    // lastes på nytt. I noen tilfeller vil ikke tjenesteeier rekke å foreta oppdatering av elementet innen
                    // rimelig tid, og det kan være hensiktsmessig å hinte dette til klienten slik at den vise noe i UI
                    // til sluttbrukeren umiddelbart og indikere at endringen kommer sere.
                    "isDialogUpdateDelayed": false, 

                    // Hvis oppgitt, vil vise en continue/cancel prompt til sluttbruker som må bekreftes før handlinge blir 
                    // forsøkt utført
                    "prompt": [ { "code": "nb_NO", "value": "Vil du sende lesebekreftelse?" } ]

                },

                "url": "https://example.com/some/deep/link/to/dialogs/123456789/confirmReceived"
            },
            { 
                "action": "delete",
                "priority": "tertiary",
                "title": [ { "code": "nb_NO", "value": "Avbryt" } ],

                // Spesialisering av writeAction, hinter til SBS-et at det ikke vil være aktuelt å laste dialogen på nytt, 
                // men umiddelbart gå tilbake til listevisning. Bruker også DELETE som method. 
                "isDeleteAction": true,
                "url": "https://example.com/some/deep/link/to/dialogs/123456789" 
            }
        ],
        "api": [ 
            { 
                "action": "open", // Denne referes til i XACML-policy (som action)
                "endpoints": [ 
                    // Det støttes ulike parallelle versjoner av API-endepunkter. Første i lista er å regne som 
                    // siste versjon og anbefalt brukt. GUI-actions er ikke versjonerte.
                    {
                        "version": "v2",
                        "actionUrl": "https://example.com/api/v2/dialogs/123456789",
                        "method": "GET",

                        // Indikerer hva API-konsumenter kan forvente å få slags svar
                        "responseSchema": "https://schemas.example.com/dialogservice/v2/dialogservice-prelim-receipt.json" , 
                        // Lenke til dokumentasjon for denne actionen
                        "documentationUrl": "https://api-docs.example.com/v2/dialogservice/open-action"                         
                    },
                    {
                        "version": "v1",

                        // Tjenestetilbyder kan indikerer om en versjon er utgående, og evt oppgi en dato 
                        // for når versjonen ikke lengre støttes
                        "deprecated": true, 
                        "sunsetDate": "2024-12-31T23:59:59.999Z",
                        "actionUrl": "https://example.com/api/v1/dialogs/123456789",
                        "method": "GET",

                        // Indikerer hva API-konsumenter kan forvente å få slags svar
                        "responseSchema": "https://schemas.example.com/dialogservice/v1/dialogservice-prelim-receipt.json" , 
                        // Lenke til dokumentasjon for denne actionen
                        "documentationUrl": "https://api-docs.example.com/v1/dialogservice/open-action",
                    },
                ]
            },
            { 
                "action": "confirm",
                // Hvis handlingen omfatter/berører et spesifikt dialogelement
                // kan det oppgis en identifikator til dette her.
                "dialogElementId": "4558064e-4049-4075-a58f-d67bda83f88c",
                "endpoints": [
                    {
                        "version": "v1",
                        "method": "POST",
                        "actionUrl": "https://example.com/api/dialogs/123456789/confirmReceived/23456",
                        "documentationUrl": "https://api-docs.example.com/dialogservice/confirm-action"
                        // Ingen requestmodell impliserer tom body
                    }
                ]                
            },
            {
                "action": "submit", // Denne kan refereres i XACML-policy
                "endpoints": [
                    {
                        "version": "v1",
                        "action": "submit", // Denne kan refereres i XACML-policy
                        "actionUrl": "https://example.com/api/dialogs/123456789",
                        "method": "POST",
                
                        // Indikerer hva API-et forventer å få som input på dette endepunktet
                        "requestSchema": "https://schemas.example.com/dialogservice/v1/dialogservice.json", 
                        "responseSchema": "https://schemas.example.com/dialogservice/v1/dialogservice-prelim-receipt.json" 
                    }
                ]
            },
            { 
                "action": "delete",
                "endpoints": [
                    {
                        "version": "v1",
                        "method": "DELETE",
                        // Merk dette vil kreve at org gjør bakkanal-kall for å slette dialogen
                        "actionUrl": "https://example.com/api/dialogs/123456789"
                    }
                ]
            }
        ]
    },
    // Dette er en lineær, "append-only" historikk vedlikeholdt av tjenesteeier som indikerer hva som logisk har skjedd 
    // gjennom den aktuelle dialogen. 
    //
    // En rekke ulike typer aktivitet gjenkjennes, og kan brukes for å indikere innsendinger, utsendinger (enten som 
    // tilbakemelding på en innsending, eller frittstående), feilsituasjoner og annen generell informasjon.
    //
    // Dette tilgjengeliggjøres sluttbruker gjennom GUI og API, og vil  slås sammen med 
    // aktivitet foretatt i dialogporten, som kan være:
    // - videredelegering av instansen
    // - dialogen åpnes for første gang
    //
    // Se dialogporten-get-single-response.json for flere eksempler.
    "activityHistory": [
        { 
            // Tjenestetilbyder kan selv oppgi identifikator
            "activityId": "fc6406df-6163-442a-92cd-e487423f2fd5",

            "activityDateTime": "2022-12-01T10:00:00.000Z",
            // Her kan det være ulike typer som medfører ulik visning i GUI. Følgende typer gjenkjennes:            
            // - submission:     Refererer en innsending utført av party som er mottatt hos tjenestetilbyder.
            // - feedback:       Indikerer en tilbakemelding fra tjenestetilbyder på en innsending.
            // - information:    Informasjon fra tjenestetilbyder, ikke (direkte) relatert til noen innsending.  
            // - error:          Brukes for å indikere en feilsituasjon, typisk på en innsending. Inneholder en
            //                   tjenestespesifikk activityErrorCode.
            // - closed:         Indikerer at dialogen er lukket for videre endring. Dette skjer typisk ved fullføring
            //                   av dialogen, eller sletting.
            //
            // Typer som kun kan settes av Dialogporten selv som følge av handlinger utført av bruker:
            // - seen:           Når dialogen først ble hentet og av hvem. Kan brukes for å avgjøre om purring 
            //                   skal sendes ut, eller internt i virksomheten for å tracke tilganger/bruker.
            //                   Merk at dette ikke er det samme som "lest", dette må tjenestetilbyder selv håndtere 
            //                   i egne løsninger.
            // - forwarded:      Når dialogen blir videresendt (tilgang delegert) av noen med tilgang til andre
            "activityType": "submission",

            // Indikerer hvem som står bak denne aktiviteten. Fravær av dette feltet indikerer at det er tjenesteilbyder
            // som har utført aktiviteten.
            "performedBy": [ { "code": "nb_NO", "value": "Anne Olsen" } ],
            
            // Vilkårlig streng som er ment å være maskinlesbar, og er en tjenestespesifikk kode som gir ytterligere
            // informasjon om hva slags aktivitetstype dette innslaget er
            "extendedActivityType": "SKE-1234-received-precheck-ok",

            // Hvis denne aktiviteten har direkte avstedkommet et dialogelement, kan dette oppgis her. Det valideres at 
            // oppgitt dialogElementId også oppgis i "dialogElements" i samme request. Denne identifikatoren blir lagt ved 
            // events som genereres.
            "dialogElementId": "b323cef4-adbd-4d2c-b33d-5c0f3b11171b",

            // Menneskelesbar beskrivelse av aktiviteten
            "activityDescription": [ { "code": "nb_NO", "value": "Innsending er mottatt og sendt til behandling" } ]
        }
    ],
    // Dette er ulike innstillinger som kun kan oppgis og er synlig for tjenesteeier
    "configuration": {

        // Tjenestetilbyder kan oppgi et selvpålagt tokenkrav, som innebærer at dette dialogen vil kreve at det 
        // autoriseres med et Maskinporten-token som inneholder følgende scopes i tillegg til 
        "serviceProviderScopesRequired": [ "serviceprovider:myservice" ],

        // Når blir dialogen synlig hos party. Muliggjør opprettelse i forveien og samtidig tilgjengeliggjøring 
        // for mange parties.
        "visibleDateTime": "2022-12-01T12:00:00.000Z"
    }
}

dialog-get-single-response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
// Modellene er hovedsaklig like for SBS og tjenesteier, men er på ulike endepunkter (pga. autorisasjon)


// GET /dialogporten/api/v1/enduser/dialogs/e0300961-85fb-4ef2-abff-681d77f9960e
{
    "id": "e0300961-85fb-4ef2-abff-681d77f9960e",
    "org": "digdir", // Identifikator for tjenestetilbyder
    "serviceResource": "urn:altinn:resource:super-simple-service", 
    "process": {
        "id": "some-arbitrary-id",
        "order": 1,
        "name": [ { "code": "nb_NO", "value": "Navn på prosess." } ]
    },
    "party": "urn:altinn:organization:identifier-no::991825827",
    "externalReference": "123456789",
    "status": "in-progress",
    "extendedStatus": "SKE-ABC",
    "dates": {
        "createdDateTime": "2022-12-01T10:00:00.000Z",
        "updatedDateTime": "2022-12-01T10:00:00.000Z",
        // Sist meldingen ble "lest", altså ekspandert i UI eller hentet via detailsUrl i API. Hvis ikke oppgitt, eller 
        // readDateTime < updatedDateTime vises typisk dialogen som ulest/oppdatert i GUI.
        "readDateTime": "2022-12-01T10:00:00.000Z", 
        "dueDateTime": "2022-12-01T12:00:00.000Z"
    },
    "content": [
        {
            "type": "Title",
            "value": [{ "code": "nb_NO", "value": "En eksempel på en tittel" } ]
        },
        {
            "type": "Summary",
            "value": [{ "code": "nb_NO", "value": "Kort tekst for oppsummering" } ]
        },
        {
            "type": "AdditionalInfo",
            "value": [{ "code": "nb_NO", "value": "Ytterligere informasjon med <em>begrenset</em> HTML-støtte.
                Dette innholdet vises kun i detaljvisning av dialogen." } ]
        },
        {
            "type": "SenderName",
            "value": [{ "code": "nb_NO", "value": "Overstyrt avsendernavn (bruker default tjenesteeiers navn)" } ]
        }
    ],
    // Et token med EdDSA-algoritme, signert av et sertifikat tilgjengelig på et .well-known-endepunkt. 
    // Brukes i utgangspunktet for writeActions, front channel embeds og SignalR
    "dialogToken": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ....",
    "dialogElements": [
        {
            "dialogElementId": "5b5446a7-9b65-4faf-8888-5a5802ce7de7",
            "dialogElementType": "form-type-1",
            "displayName": [ { "code": "nb_NO", "value": "Innsendt skjema" } ],
            "urls": [
                {
                    "consumerType": "gui",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/5b5446a7.pdf",
                    "contentType": "application/pdf"
                },
                {
                    "consumerType": "api",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/5b5446a7.xml",
                    "contentType": "application/json"
                }
            ]
        },
        {
            "authorizationAttribute": "urn:altinn:subresource:somesubresource",
            "urls": [
                {
                    "consumerType": "gui",
                    "frontChannelEmbed": true,
                    "url": "https://example.com/api/dialogs/123456789/user-instructions",

                    // Ved front channel embeds må content type oppgis. I første omgang støttes 
                    // bare text/markdown (CommonMark-variant), men på sikt kan flere typer innføres. 
                    // Arbeidsflate/SBS vil ha ansvaret for å sikkerhet håndtere innholdet
                    "contentType": "text/markdown"
                }
            ]
        }, 
        {
            "dialogElementId": "cd6bf231-2347-4131-8ccc-513a6345ef0b",
            "dialogElementType": "form-type-1",
            "displayName": [ { "code": "nb_NO", "value": "Innsendt korrigering #1" } ],
            "urls": [
                {
                    "consumerType": "gui",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/cd6bf231.pdf",
                    "contentType": "application/pdf"
                },
                {
                    "consumerType": "api",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/cd6bf231.xml",
                    "contentType": "application/json"
                }
            ]
        },
        {
            "dialogElementId": "22366651-c1b6-4812-a97d-5ed43fc4fe57",
            "dialogElementType": "error-list",   
            "relatedDialogElementId": "cd6bf231-2347-4131-8ccc-513a6345ef0b",
            "authorizationAttribute": "urn:altinn:subresource:someothersubresource",
            "uris": [
                {
                    "consumerType": "api",
                    "uri": "https://example.com/api/dialogs/123456789/dialogelements/22366651.xml",
                    "contentType": "application/json"
                }
            ]
        },
        {
            "dialogElementId": "a8e0ed0d-1b26-4132-9823-28a5e8ecb24e",            
            "displayName": [ { "code": "nb_NO", "value": "Innsendt korrigering #2" } ],
            "dialogElementType": "skd:form-type-1",
            "urls": [
                {
                    "consumerType": "gui",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/a8e0ed0d.pdf",
                    "contentType": "application/pdf"
                },
                {
                    "consumerType": "api",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/a8e0ed0d.xml",
                    "contentType": "application/xml"
                }
            ]            
        },
        {
            "dialogElementId": "a12fce1f-b2de-4837-bdd8-8743f80d74fc",            
            "displayName": [ { "code": "nb_NO", "value": "Vedtaksbrev" } ],            
            "dialogElementType": "skd:form-type-1",
            "authorizationAttribute": "urn:altinn:subresource:somesubresource",
            // Indikerer om autentisert bruker er autorisert til å lese (har action "read") - finnes bare i response-modell for 
            // sluttbrukere og populeres av Dialogporten utfra policy. Dette er et hint for GUI-implementasjoner som da kan 
            // velge å skjule/gråe ut elementer som ikke er tilgjengelige.
            "isAuthorized": false,
            "urls": [
                {
                    "consumerType": "gui",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/a12fce1f.pdf",
                    "mimeType": "application/pdf"                        
                },
                {
                    "consumerType": "api",
                    "url": "https://example.com/api/dialogs/123456789/dialogelements/a12fce1f.xml"
                }
            ]
        }
    ],
    "actions": {
        "gui": [ 
            { 
                "action": "open", // Denne kan refereres i XACML-policy
                "priority": "primary", // Dette bestemmer hvordan handlingen presenteres.
                "title": [ { "code": "nb_NO", "value": "Åpne i dialogtjeneste" } ],
                "url": "https://example.com/some/deep/link/to/dialogs/123456789"
            },
            {
                "action": "confirm",
                "authorizationAttribute": "urn:altinn:subresource:somesubresource",
                // Indikerer om autentisert bruker er autorisert å aksessere oppgitt url  - finnes bare i response-modell for 
                // sluttbrukere og populeres av Dialogporten utfra policy. Dette er et hint for GUI-implementasjoner som da kan 
                // velge å skjule/gråe ut elementer som ikke er tilgjengelige.
                "isAuthorized": false,
                "priority": "secondary",
                "title": [ { "code": "nb_NO", "value": "Bekreft mottatt" } ],
                "writeAction": {
                    "method": "post",
                    "isDialogUpdateDelayed": false,
                    "prompt": [ { "code": "nb_NO", "value": "Vil du sende lesebekreftelse?" } ]
                },
                // Et token med EdDSA-algoritme, signert av et sertifikat tilgjengelig på et .well-known-endepunkt
                // Blir kun generert på dialogElementer med frontChannelEmbed eller write actions
                "dialogToken": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ....",
                "url": "https://example.com/some/deep/link/to/dialogs/123456789/confirmReceived"
            },
            { 
                "action": "delete",
                "priority": "tertiary",
                "title": [ { "code": "nb_NO", "value": "Avbryt" } ],
                "isDeleteAction": true,
                // Et token med EdDSA-algoritme, signert av et sertifikat tilgjengelig på et .well-known-endepunkt
                // Blir kun generert på dialogElementer med frontChannelEmbed eller write actions
                "dialogToken": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ....",
                "url": "https://example.com/some/deep/link/to/dialogs/123456789"
            }
        ],
        "api": [ 
            { 
                "action": "open",
                "endpoints": [ 
                    {
                        "version": "v2",
                        "actionUrl": "https://example.com/api/v2/dialogs/123456789",
                        "method": "GET",
                        "responseSchema": "https://schemas.altinn.no/dialogs/v2/dialogs.json", 
                        "documentationUrl": "https://api-docs.example.com/v2/dialogservice/open-action"                         
                    },
                    {
                        "version": "v1",
                        "deprecated": true, 
                        "sunsetDate": "2024-12-31T23:59:59.999Z",
                        "actionUrl": "https://example.com/api/v1/dialogs/123456789",
                        "method": "GET",
                        "responseSchema": "https://schemas.altinn.no/dialogs/v1/dialogs.json", 
                        "documentationUrl": "https://api-docs.example.com/v1/dialogservice/open-action",
                    },
                ]
            },
            { 
                "action": "confirm",
                "endpoints": [
                    {
                        "version": "v1",
                        "method": "POST",
                        "isAuthorized": false,
                        "actionUrl": "https://example.com/api/dialogs/123456789/confirmReceived",
                        "documentationUrl": "https://api-docs.example.com/dialogservice/confirm-action"
                    }
                ]                
            },
            {
                "action": "submit", // Denne kan refereres i XACML-policy
                "endpoints": [
                    {
                        "version": "v1",
                        "action": "submit", // Denne kan refereres i XACML-policy
                        "actionUrl": "https://example.com/api/dialogs/123456789",
                        "method": "POST",
                        "requestSchema": "https://schemas.example.com/dialogservice/v1/dialogservice.json", 
                        "responseSchema": "https://schemas.altinn.no/dialogs/v1/dialogs.json" 
                    }
                ]
            },
            { 
                "action": "delete",
                "endpoints": [
                    {
                        "version": "v1",
                        "method": "DELETE",
                        "actionUrl": "https://example.com/api/dialogs/123456789"
                    }
                ]
            }
        ]
    },
    // Se dialogporten-create-request.json for feltforklaringer
    "activityHistory": [
        {
            "activityId": "fc6406df-6163-442a-92cd-e487423f2fd5",
            "activityDateTime": "2022-12-01T10:00:00.000Z",
            "activityType": "submission",
            "performedBy": [ { "code": "nb_NO", "value": "Anne Olsen" } ],
            "extendedActivityType": "SKE-1234-received-precheck-ok",
            "dialogElementId": "5b5446a7-9b65-4faf-8888-5a5802ce7de7",
            "activityDescription": [ { "code": "nb_NO", "value": "Innsending er mottatt og sendt til behandling" } ]
        }
        { 
            "activityId": "7f91fb5e-4c79-4c01-82aa-84911ef13b75",
            "activityDateTime": "2022-12-01T10:15:00.000Z",
            "activityType": "seen",
            "performedBy": [ { "code": "nb_NO", "value": "Anne Olsen" } ],
        },
        { 
            "activityId": "e13b308b-3873-460b-8486-205ce934f4b0",
            "activityDateTime": "2022-12-01T10:16:00.000Z",
            "activityType": "forwarded",
            "performedBy": [ { "code": "nb_NO", "value": "Anne Olsen" } ],
            // Mottaker av delegering
            "recipient": [ { "code": "nb_NO", "value": "Kari Pettersen" } ],
        },
        { 
            "activityId": "ab06af62-6067-477f-b18c-bf54222273b9",            
            "activityDateTime": "2022-12-01T11:00:00.000Z",
            "activityType": "feedback",
            // Feedback-typer har vanligvis en referanse til en submission-aktivitet som dette er feedback for
            "relatedActivityId": "fc6406df-6163-442a-92cd-e487423f2fd5",
            "extendedActivityType": "SKE-2456-need-form-RF1337",
            "activityDescription": [ { "code": "nb_NO", "value": "Behandling er utført. Ytterligere opplysninger kreves." } ],
        },
        { 
            "activityId": "f6ef1a96-df3a-4d38-830f-853b5d090e16",
            "activityDateTime": "2022-12-01T12:00:00.000Z",
            "activityType": "submission",
            "extendedActivityType": "SKE-2456-received-precheck-ok",
            "dialogElementId": "cd6bf231-2347-4131-8ccc-513a6345ef0b",
            "activityDescription": [ { 
                "code": "nb_NO", 
                "value": "Innsending av ytterligere opplysninger er mottatt og sendt til behandling." 
            } ]
        },
        { 
            "activityId": "7d971b46-fb66-4a97-8f5e-333c1df54678",
            "activityDateTime": "2022-12-01T13:00:00.000Z",
            "activityType": "error",
            // Feilmeldinger har også vanligvis en referanse til en tidligere aktivitet og/eller 
            // dialogelement som var årsak til at feilsituasjonen oppstod
            "relatedActivityId": "f6ef1a96-df3a-4d38-830f-853b5d090e16",
            // Feilmeldinger kan også ha et eget dialogelement som inneholder en strukturert feilmelding 
            "dialogElementId": "22366651-c1b6-4812-a97d-5ed43fc4fe57",            
            "activityErrorCode": "SKE-error-12345",
            "activityDescription": [ { 
                "code": "nb_NO", 
                "value": "Saksbehandling har avdekket feil i innsending." 
            } ]
        },
        { 
            "activityId": "4ce2e110-21c5-4783-94ed-b2a8695abb8a",
            "activityDateTime": "2022-12-01T14:00:00.000Z",
            "activityType": "submission",
            "extendedActivityType": "SKE-2456-received-precheck-ok",
            "dialogElementId": "a8e0ed0d-1b26-4132-9823-28a5e8ecb24e",
            "activityDescription": [ { 
                "code": "nb_NO", 
                "value": "Innsending av ytterligere opplysninger er mottatt og sendt til behandling." 
            } ]
        },
        { 
            "activityId": "20c94e10-b95d-4cd0-b469-b4caa4532c4e",
            "activityDateTime": "2022-12-01T15:00:00.000Z",
            "activityType": "feedback",
            "extendedActivityType": "SKE-2456-final-ok",
            "dialogElementId": "a12fce1f-b2de-4837-bdd8-8743f80d74fc",
            "activityDescription": [ { 
                "code": "nb_NO", 
                "value": "Saksbehandling er utført og vedtak er fattet, se vedlagt vedtaksbrev." 
            } ]
        },
        { 
            "activityId": "b6d96fc1-edac-407e-aa96-147f07878092",
            "activityDateTime": "2022-12-22T15:00:00.000Z",
            // En "closed"-oppføring knyttes som regel med at en dialog settes som "cancelled" eller "completed", 
            // og indikerer at den konkrete dialogen er avsluttet.
            "activityType": "closed",
            "activityDescription": [ { 
                "code": "nb_NO", 
                "value": "Klagefrist utløpt, sak avsluttet." 
            } ]
        }
    ],
    // Dette er ulike innstillinger som kun kan oppgis og er synlig for tjenesteeier. Se de-create-request for informasjon om feltene.
    "configuration": {        
        "visibleDateTime": "2022-12-01T12:00:00.000Z"
    },
    // HAL til relatert informasjon
    "_links": {
        "self": { "href": "/dialogporten/api/v1/enduser/dialogs/e0300961-85fb-4ef2-abff-681d77f9960e" },        
        
        // eget endepunkt for varslingslogg for dialogen
        "notificationlog": { "href": "/dialogporten/api/v1/enduser/dialogs/e0300961-85fb-4ef2-abff-681d77f9960e/notificationlog" }, 

        // Dyplenke til portalvisning for dialogen i Dialogporten
        "serviceresource": { "href": "/resourceregistry/api/v1/resource/super-simple-service/" }, 

        // Dyplenke til portalvisning for dialogen i Dialogporten
        "selfgui": { "href": "https://www.dialogporten.no/?expandDialog=e0300961-85fb-4ef2-abff-681d77f9960e" }, 

        // Dyplenke til portalvisning for dialogen hos tjenesteeier
        "externalgui": { "href": "https://example.com/some/deep/link/to/dialogs/123456789" } 
    }
}

dialog-patch-request-01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Input modell som tjenesteeiere oppgir for å endre/oppdatere en dialog.

// I dette eksemplet er det en dialogtjeneste hvor det å "sende inn" er en egen handling, som typisk ikke er 
// tilgjengelig før alt er fylt ut, validert og signert. "Send inn" blir satt til primærhandlingen i GUI. 
// POST vil ikke kunne realiseres i framkanal (pga SSO og samesite-problematikk for cookies), så 
// tjenesteeieren må vurdere om man ønsker at dette GET-kallet skal medføre en tilstandsendring direkte, 
// eller om brukeren må bekrefte dette etter omdiriggering. Til slutt blir da brukeren sendt til en eller 
// annen kvitteringsside hos tjenesteeier, som da også har satt dialogen som "completed" via et bakkanal-kall

// PATCH /dialogporten/api/v1/serviceowner/dialogs/e0300961-85fb-4ef2-abff-681d77f9960e
{
    "actions": {
        "gui": [            
            { 
                "action": "send",
                "priority": "primary",
                "title": [ { "code": "nb_NO", "value": "Send inn" } ],
                "url": "https://example.com/some/deep/link/to/dialogs/123456789/send"
            },
            { 
                "action": "open", 
                "priority": "secondary",
                "title": [ { "code": "nb_NO", "value": "Se over før innsending" } ],
                "url": "https://example.com/some/deep/link/to/dialogs/123456789"
            }, 
            { 
                "action": "delete",
                "priority": "tertiary",
                "title": [ { "code": "nb_NO", "value": "Avbryt" } ],
                "isDeleteAction": true, 
                "url": "https://example.com/some/deep/link/to/dialogs/123456789" 
            }
        ],
        "api": [ 
            { 
                "action": "open",
                "endpoints": [
                    {
                        "actionUrl": "https://example.com/api/dialogs/123456789",
                        "method": "GET",
                        "responseSchema": "https://schemas.altinn.no/dialogs/v1/dialogs.json",
                        "documentationUrl": "https://api-docs.example.com/dialogservice/open-action"
                    }
                ]
            },
            { 
                "action": "confirm",
                "endpoints": [
                    {
                        "method": "POST",
                        "actionUrl": "https://example.com/api/dialogs/123456789/confirmReceived",
                        "documentationUrl": "https://api-docs.example.com/dialogservice/confirm-action"
                    }
                ]
            },
            { 
                "action": "submit",
                "endpoints": [
                    {
                        "actionUrl": "https://example.com/api/dialogs/123456789/submit",
                        "method": "POST",
                        "requestSchema": "https://schemas.example.com/dialogservice/v1/dialogservice.json",
                        "responseSchema": "https://schemas.altinn.no/dialogs/v1/dialogs.json" 
                    }
                ]
            },
            { 
                "action": "delete",
                "endpoints": [
                    {
                        "method": "DELETE",
                        "actionUrl": "https://example.com/api/dialogs/123456789"
                    }
                ]
            }
        ]
    },
    // Merk at vi her bryter med vanlig PATCH/merge-semantikk; her skal det kun legges til et element
    // Det reelle API-et vil støtte POST på et activityhistory-endepunkt, samt JSON PATCH for å kunne gjøre alt atomisk
    "activityHistory": [
        { 
            "activityDateTime": "2022-12-01T10:00:00.000Z",
            "activityType": "information",
            "activityType": "SKE-34355",
            "performedBy": [ { "code": "nb_NO", "value": "Anne Olsen" } ],
            "activityDescription": [ { "code": "nb_NO", "value": "Dokumentet 'X' ble signert og kan sendes inn" } ]
        }
    ]
}

dialog-patch-request-02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// PATCH /dialogporten/api/v1/serviceowner/dialogs/e0300961-85fb-4ef2-abff-681d77f9960e
{
    "status": "completed",
    "activityHistory": [
        { 
            "activityDateTime": "2022-12-22T15:00:00.000Z",
            "activityType": "closed",
            "extendedActivityType": "SKE-5678",
            "activityDescription": [ { 
                "code": "nb_NO", 
                "value": "Klagefrist utløpt, sak avsluttet." 
            } ]
        }
    ]
}

dialog-search-response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Listemodell som brukes i dialogboks-søk. Presis paginering er antagelig ikke mulig pga. behov for individuell 
// autorisasjon per dialog, men det burde være en eller annen "next"-mekanisme som lar et SBS iterere gjennom en liste.

// GET /dialogporten/api/v1/enduser/dialogs/?search=....
[
    {
        "id": "e0300961-85fb-4ef2-abff-681d77f9960e",
        "org": "digdir",
        "serviceResource": "super-simple-service",
        "externalReference": "someReference",
        "party": "urn:altinn:person:identifier-no::12018212345",        
        "dates": {
            "createdDateTime": "2022-12-01T10:00:00.000Z",
            "updatedDateTime": "2022-12-01T10:00:00.000Z",
            "dueDateTime": "2022-12-01T12:00:00.000Z"  
        },
        "status": "in-progress",
        "extendedStatus": "SKE-ABC",
        // Inneholder ikke "AdditionalInfo", denne må hentes i detailsUrl
        "content": [
            {
                "type": "Title",
                "value": [{ "code": "nb_NO", "value": "En eksempel på en tittel" } ]
            },
            {
                "type": "Summary",
                "value": [{ "code": "nb_NO", "value": "Kort tekst for oppsummering" } ]
            },
            {
                "type": "SenderName",
                "value": [{ "code": "nb_NO", "value": "Overstyrt avsendernavn (bruker default tjenesteeiers navn)" } ]
            },
        ],
        "detailsUrl": "/dialogporten/api/v1/enduser/dialogs/e0300961-85fb-4ef2-abff-681d77f9960e"
    }
]

instantiate-request

1
2
3
4
5
6
7
8
9
10
11
12
13
// Dette er modellen som SBS sender inn til et felles endepunkt hos Altinn for å instansiere en navngitt tjeneste.
// Altinn gjør en enkel proxy av dette kallet til instansierings-endepunktet som tjenesteeier har registrert på den 
// aktuelle tjenesten. Altinn proxyer også svaret, som skal være enten en 201 Created og en DE-response-modell, eller
// en 4xx/5xx med en RFC7807-kompatibel feilmelding.
{
    "serviceResource": "urn:altinn:resource:super-simple-service",
    "party": "urn:altinn:person:identifier-no::12018212345",
    // Hvis det ifm instansiering kreves noen parametre kan disse oppgis her. Disse sendes verbatim til instatiationUrl 
    // (kun gjenstand for størrelsesbegrensninger). All logikk og øvrig validering foretas av tjenesteeier.
    "inputParameters": { 
        "someKey": "someValue"
    }
}

notification-create-request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Input modell som tjenesteeiere oppgir for å opprette en ny varsling knytte til en dialog.
// KRR / KoFuVI / varslingsadresser oppgitt i Altinn legges til grunn.
// Man oppgir minst én av sms, email og push. Ytterligere varslinger kan sendes når som helst.
// Kun konsumenter som er autorisert for den aktuelle dialogen vil motta varsel.

// POST /dialogporten/api/v1/serviceowner/dialogs/{dialogId}/notifications
{
    // Valgfri identifikator som tjenestetilbyder kan oppgi. Kan brukes for å unngå duplikatutsending.
    "notificationId": "79921fae-631a-4f8b-8db5-e359f2336658",

    // XACML-ressurs i poliy knyttet til dialog som det tilgang til (vilkårlig action) for å kunne motta varsel 
    "subresource": "urn:altinn:subresource:some-xaml-resouce",
    "sms": {
            "text": [ { "code": "nb_NO", "value": "dette kommer på sms" } ],
            
            // Hvis avsender-felt skal være noe annet enn navn på tjenesteeier kan dette oppgis her. 
            // Valideres opp mot whitelist knyttet til autentisert org.
            "from": [ { "code": "nb_NO", "value": "Etaten" } ]
    },
    "email": {
            "subject": [ { "code": "nb_NO", "value": "Signeringsoppdrag for Omsetningsrapportering" } ],
            "template": "general-notification",
            "tokens": [
                { "name": "header", "value": [ { "code": "nb_NO", "value": "Signeringsoppdrag for Omsetningsrapportering" } ] },
                { "name": "body", "value": [ { "code": "nb_NO", "value": "Hei !<br><br>Du er bedt om å signere for  i Dialogporten" } ] } 
            ]
    },
    "push": {
        // Basert på https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification
        "title": [ { "code": "nb_NO", "value": "Tittel på notifikasjon" } ],
        "body": [ { "code": "nb_NO", 
            "value": "Dette er første linje\nDette er andre linje, sendt til " } ],
        "icon": "https://example.com/some-icon-atleast-192x192.png",
        // Valgfri URL som bruker blir sendt til hvis notifikasjonen klikkes på. 
        "notificationClickUrl": "https://example.com/some/deep/link/to/dialogues/123456789"
    }
}

notifications-get-response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Logg-modell som brukes for å hente liste over sendte varslinger

// GET /dialogporten/api/v1/enduser/dialogs/{dialogId}/notifications
{
    "sms": [
        { 
            "sentDateTime": "2022-12-01T10:00:00.000Z",
            "status": "pending",
            "notification": {
                "text": "dette kommer på sms",
                "from": "Etaten" 
            }
        }
    ],
    "email": [
        {
            "sentDateTime": "2022-12-01T10:00:00.000Z",
            "status": "ok",
            "notification": {
                "subject": "emnefeltet på e-post" ,
                "template": "some-email-template",
                "tokens": [
                    { "name": "header", "value": "dette er en header" },
                    { "name": "body", "value": "Hei !" } 
                ]
            }
        }
    ],
    "push": [
        {
            "sentDateTime": "2022-12-01T10:00:00.000Z",
            "status": "ok",
            "notification": {            
                "title": "Notification title",
                "body": "Simple piece of body text.\nSecond line of body text :)",
                "icon": "https://example.com/some-icon-atleast-192x192.png",
                "notificationClickUrl": "https://example.com/some/deep/link/to/dialogues/123456789"
            }
        }    
    ]
}

serviceresource-create-request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Input modell her vil være en ServiceResource som beskrevet på 
// https://docs.altinn.studio/authorization/modules/resourceregistry/
// Modellen må utvides med en "instantiationUrl", som er lagt til under.

// POST /resourceregistry/api/v1/resource
{
    "identifier": "super-simple-service",
    "title": [
        {
            "title": "Tittel på tjenesten",
            "language": "nb-NO"
        }
    ],
    "description": [
        {
            "language": "nb-NO",
            "description": "En beskrivelse av tjenesten"
        }
    ],
    "hasCompetentAuthority": {
        "organization": "991825827",
        "orgcode": "digdir"
    },
    "contactpoint": [
        {
            "phone": "1231324",
            "email": "super-simple-service@example.com"
        }
    ],
    "isPartOf": "someportal",
    "homepage": "https://example.com/about_super-simple-service",
    "status": "Completed",
    "thematicArea": [],
    "type": [],
    "sector": [],
    "keyword": [
        {
            "keyword": "delegation"
        },
        {
            "keyword": "access management"
        }
    ],
    "instantiationUrl": "https://example.com/api/v1/super-simple-service/instantiate"
}

// Velykket innsending returnerer en 201 Created med Location-lenke til den aktuelle tjenesteressursen. Policy settes så på 
// tjenesteressursen med et kall som inneholder en XACML-policy til: 
// POST /resourceregistry/api/v1/resource/super-simple-service/policy

Eksempel-case

Eksempel 01

Eksempel-flyt basert på Skatts case ("superenkel innsending") med events

Gå til case

Eksempel 02

Eksempel-flyt basert på Primærnæringsoppgave Egg

Gå til case

Eksempel 03

Eksempel-case som beskriver to signeringssteg for ulike parter

Gå til case