-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Guide: Correspondence integration (#1950)
- Loading branch information
1 parent
d83b894
commit c200668
Showing
16 changed files
with
568 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
content/altinn-studio/guides/integration/correspondence/_index.en.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
36 changes: 36 additions & 0 deletions
36
content/altinn-studio/guides/integration/correspondence/_index.nb.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
217 changes: 217 additions & 0 deletions
217
content/altinn-studio/guides/integration/correspondence/maskinporten.en.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
); | ||
``` |
Oops, something went wrong.