Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guide: Correspondence integration #1950

Merged
merged 9 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Before setting up eFormidling you will need to have the following set up:

### Maskinporten Integration

In order to enable eFormidling in your application you will need to [setup an integration between your app and Maskinporten](/altinn-studio/guides/integration/maskinporten-app-integration/).
In order to enable eFormidling in your application you will need to [setup an integration between your app and Maskinporten](/altinn-studio/guides/integration/maskinporten/).

* **NB!** In `Program.cs` add the following instead of what is described in the steps above in the `RegisterCustomAppServices`-method:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Before setting up eFormidling you will need to have the following set up:

### Maskinporten Integration

In order to enable eFormidling in your application you will need to [setup an integration between your app and Maskinporten](/altinn-studio/guides/integration/maskinporten-app-integration/).
In order to enable eFormidling in your application you will need to [setup an integration between your app and Maskinporten](/altinn-studio/guides/integration/maskinporten/).

* **NB!** In `Program.cs` add the following instead of what is described in the steps above in the `RegisterCustomAppServices`-method:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ required prerequisites are met.
owner.*

If step 2 and 3 of the technical requirements are missing see
section [Maskinporten-App Integration](../../../integration/maskinporten-app-integration)
section [Maskinporten-App Integration](../../../integration/maskinporten)

\* _If the end user of application A have the required roles to instantiate application B on behalf of the intended
recipient, you can skip these technical requirements_
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Før du starter på den tekniske implementeringen, må du sørge for at de nødv
som skal sende forespørsler til en annen applikasjon, hvor forespørslene må autoriseres av applikasjonenseier.*

Hvis trinn 2 og 3 av de tekniske kravene mangler, se
seksjonen [Maskinporten-App Integrering](../../../integration/maskinporten-app-integration)
seksjonen [Maskinporten-App Integrering](../../../integration/maskinporten)

\* _Hvis sluttbrukeren av applikasjon A har de nødvendige rollene for å instansiere applikasjon B på vegne av den
tiltenkte
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Integrate an Altinn app with Correspondence
linktitle: Correspondence
description: How to setup an integration between an Altinn App and Correspondence.
weight: 100
toc: true
---

This guide details how to integrate the [correspondence messaging service](/correspondence/) with an Altinn application.
This integration enables an app to securely send digital messages and attachments to both organisations and individuals.

## Prerequisites
1. An applicable [Altinn resource](#altinn-resource)
2. [Altinn.App.Api](https://www.nuget.org/packages/Altinn.App.Api) and [Altinn.App.Core](https://www.nuget.org/packages/Altinn.App.Core) _v8.5.0_ or greater

### Altinn Resource
When sending a correspondence, it needs to be tied to an Altinn resource. This resource controls the access policy for
the Correspondence, which is evaluated for both senders and receivers.

Please refer to the [resource registration guide](/correspondence/getting-started/service-owner/#register-a-resource-in-altinn-resource-registry)
for more information on the setup process.

{{<notice info notice-paragraph-fix>}}
The resource needs to allow sender access for [your organisation](https://github.com/Altinn/altinn-cdn/blob/master/orgs/altinn-orgs.json)
and recipient access for the appropriate [role codes](https://github.com/Altinn/altinn-cdn/blob/master/authorization/subjectoptions.json).

Note that for messages sent to a person, the code `priv` should be used. For messages sent to an organisation, whichever roles
best describing your indented recipient should be used.
{{</notice>}}

## Implementation and usage
In order to use the correspondence service, the request must be authorised with an appropriate bearer token and a subscription key.

Please refer to the sections below for a detailed guide on how to achieve this:

- [Sending correspondence using Maskinporten](maskinporten)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Integrasjon av Altinn-app med Meldingstjenesten
linktitle: Meldingstjenesten
description: Hvordan sette opp en integrasjon mellom en Altinn-app og Meldingstjenesten.
weight: 100
toc: true
---

Denne veiledningen beskriver hvordan du integrerer [meldingstjenesten](/correspondence/) med en Altinn-applikasjon.
En slik integrasjon gjør det mulig for en app å sende digitale meldinger og vedlegg sikkert til både organisasjoner og enkeltpersoner.

## Forutsetninger
1. En [Altinn-ressurs](#altinn-ressurs)
2. [Altinn.App.Api](https://www.nuget.org/packages/Altinn.App.Api) og [Altinn.App.Core](https://www.nuget.org/packages/Altinn.App.Core) _v8.5.0_ eller nyere

### Altinn-ressurs
Når du sender en korrespondanse må den knyttes til en Altinn-ressurs. Denne ressursen kontrollerer tilgangsstyring for
meldinger. Disse evalueres for både avsendere og mottakere.

Vennligst se [veiledningen for ressursregistrering](/correspondence/getting-started/service-owner/#register-a-resource-in-altinn-resource-registry)
for mer informasjon om oppsett og opprettelse.

{{<notice info notice-paragraph-fix>}}
Ressursen må tillate sender-tilgang for [din organisasjon](https://github.com/Altinn/altinn-cdn/blob/master/orgs/altinn-orgs.json)
og mottaker-tilgang for ønskelige [rollekoder](https://github.com/Altinn/altinn-cdn/blob/master/authorization/subjectoptions.json).

Merk at for meldinger sendt til en person, skal koden `priv` brukes. For meldinger sendt til en organisasjon, skal de rollene
som best beskriver din tiltenkte mottaker brukes.
{{</notice>}}

## Implementasjon og bruk
For å bruke meldingstjenesten, må forespørselen autoriseres med en passende bearer-token og en abonnementnøkkel.

Vennligst se seksjonene nedenfor for en detaljert veiledning om hvordan du oppnår dette:

- [Sende meldinger ved hjelp av Maskinporten](maskinporten)
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
---
title: Using Maskinporten Authorisation with the Correspondence Service
linktitle: Using Maskinporten
weight: 100
toc: true
---

On the [previous page](../), we went through how to set up a [resource](../#altinn-resource) and the versioning requirements
for the correspondence client.

We can now proceed to the [Maskinporten setup](#maskinporten-setup) and the [application code](#application-code).

## Maskinporten Setup
In order to use the [correspondence service](/correspondence/), a [Maskinporten](/authentication/what-do-you-get/maskinporten/) client with the access to the following scopes is required:
- `altinn:serviceowner`
- `altinn:correspondence.read`
- `altinn:correspondence.write`
{.correspondence-custom-list}

To set this up, follow the general steps outlined in the [Maskinporten integration guide](../maskinporten/), with a couple of modifications described below.
- The correspondence client uses a new, internal, client to communicate with Maskinporten. Because of this, the configuration object now looks like this:

{{< code-title >}}
App/appsettings.json
{{< /code-title >}}

```json
"MaskinportenSettings": {
"authority": "https://[test.]maskinporten.no/",
"clientId": "the client id",
"jwkBase64": "base64 encoded jwk"
}
```
- The correspondence client will automatically find and use the Maskinporten client, and attempt to bind to the default
`MaskinportenSettings` configuration path.
- If you require a different configuration path, you can configure it with the `ConfigureMaskinportenClient` extension method:

{{< code-title >}}
App/Program.cs
{{< /code-title >}}

{{<highlight csharp "linenos=false,hl_lines=7-9">}}
void RegisterCustomAppServices(
IServiceCollection services,
IConfiguration config,
IWebHostEnvironment env
)
{
services.ConfigureMaskinportenClient(
"UniqueMaskinportenSettingsPath"
);
}
{{</highlight>}}
- If you require a custom configuration flow, you can make use of the available configuration delegate:

{{< code-title >}}
App/Program.cs
{{< /code-title >}}

{{<highlight csharp "linenos=false,hl_lines=7-12">}}
void RegisterCustomAppServices(
IServiceCollection services,
IConfiguration config,
IWebHostEnvironment env
)
{
services.ConfigureMaskinportenClient(config =>
{
config.Authority = "https://[test.]maskinporten.no/";
config.ClientId = "the client id";
config.JwkBase64 = "base64 encoded jwk";
});
}
{{</highlight>}}
{.connected-bullets}

## Application code
Using the dependency injection framework in .NET, you can inject an `ICorrespondenceClient` in your service.
This client can then be used to send correspondences and will be able to automatically handle the Maskinporten authorisation.

When sending a correspondence, there are a wealth of properties available. While only a handful of these are required,
the process of constructing the request itself can be a bit daunting. To assist with this, there is a
`CorrespondenceRequestBuilder` interface available.

The example below uses the builder to construct a correspondence request using the most common options: the message itself,
a notification to the recipient, and an attached file.

You will find all available options and associated documentation through IntelliSense in your favorite code editor.

### Service registration

{{< code-title >}}
App/Program.cs
{{< /code-title >}}

{{<highlight csharp "linenos=false,hl_lines=9">}}
// ...

void RegisterCustomAppServices(
IServiceCollection services,
IConfiguration config,
IWebHostEnvironment env
)
{
services.AddTransient<ITheInterfaceYouAreImplementing, CorrespondenceClientDemo>();
}
{{</highlight>}}

### Correspondence client implementation

{{< code-title >}}
App/CorrespondenceClientDemo.cs
{{< /code-title >}}

```cs
using System;
using System.Threading.Tasks;
using Altinn.App.Core.Features.Correspondence;
using Altinn.App.Core.Features.Correspondence.Builder;
using Altinn.App.Core.Features.Correspondence.Models;

namespace Altinn.App;

internal sealed class CorrespondenceClientDemo(
ICorrespondenceClient correspondenceClient
) : ITheInterfaceYouAreImplementing
{
public async Task<SendCorrespondenceResponse> SendMessage()
{
CorrespondenceAuthorisation authorisation = CorrespondenceAuthorisation.Maskinporten;
CorrespondenceRequest request = CorrespondenceRequestBuilder
.Create()
.WithResourceId("A valid resource registry identifier")
.WithSender("Sender's organisation number")
.WithSendersReference("Sender's arbitrary reference for the correspondence")
.WithRecipient("Recipient's organisation number")
.WithAllowSystemDeleteAfter(DateTime.Now.AddYears(1))
.WithContent(
language: "en",
title: "Hello from .NET 👋🏻",
summary: "The message summary",
body: "The message body with markdown support"
)
.WithNotification(
CorrespondenceNotificationBuilder
.Create()
.WithNotificationTemplate(CorrespondenceNotificationTemplate.CustomMessage)
.WithEmailSubject("New Altinn message")
.WithEmailBody(
"You have a new message in your Altinn inbox, log in to see what's new."
)
.WithSmsBody("Got 📨 in Altinn")
.WithNotificationChannel(CorrespondenceNotificationChannel.EmailPreferred)
)
.WithAttachment(
CorrespondenceAttachmentBuilder
.Create()
.WithFilename("attachment.txt")
.WithName("The attachment 📎")
.WithSendersReference("Sender's arbitrary reference for the attachment")
.WithDataType("text/plain")
.WithData("This is the attachment content"u8.ToArray())
)
.Build();

return await correspondenceClient.Send(
new SendCorrespondencePayload(request, authorisation)
);
}

public async Task<GetCorrespondenceStatusResponse> GetMessageStatus(Guid correspondenceId)
{
return await correspondenceClient.GetStatus(
new GetCorrespondenceStatusPayload(
correspondenceId,
CorrespondenceAuthorisation.Maskinporten
)
);
}
}
```

### Notes on authorisation
In the example above, we are using the `CorrespondenceAuthorisation.Maskinporten` enum to indicate that authorisation should
be automatically handled internally with Maskinporten. This is by far the easiest and most convenient authorisation method, but
it's not the only option available.

If you require custom authorisation logic while sending correspondences, you are able to supply your own delegate for this purpose.

An example of this could be if you for some reason preferred to use the legacy [external Maskinporten client](https://github.com/Altinn/altinn-apiclient-maskinporten).

Both the `SendCorrespondencePayload` and `GetCorrespondenceStatusPayload` accepts a delegate parameter. The implementation would look something like this:

```cs
// ...

new SendCorrespondencePayload(
request,
async () =>
{
TokenResponse maskinportenResponse = await maskinportenService.GetToken(
"base64 encoded jwk",
"test|prod",
"the client id",
"altinn:serviceowner altinn:correspondence.write",
null
);

TokenResponse altinnResponse = await maskinportenService.ExchangeToAltinnToken(
maskinportenResponse,
"test|prod"
);

return JwtToken.Parse(altinnResponse.AccessToken);
}
);
```
Loading
Loading