Self-service API
This is technical documentation for using the Self-service API meant for developers.
The API enables you to create single-tenant clients from a client template and to make changes to all types of clients, like rotating client keys.
An overview of all endpoints can be found here
Sample implementations in C# can be found on GitHub
Creating a client
sequenceDiagram
title Sequence diagram for client creation with the API
accTitle: Diagram that shows how you can automate client creation with the API
actor EndUser as End User
participant ClientTemplate as Client template
participant API as api.selvbetjening.nhn.no
participant Portal as selvbetjening.nhn.no
participant HelseId as helseid-sts.nhn.no
ClientTemplate ->> API: client draft (using api key) [1]
activate API
API -->> ClientTemplate: client id
deactivate API
ClientTemplate ->> Portal: Open URL in browser [2]
activate Portal
Portal ->> EndUser: Request confirmation
EndUser ->> Portal: Confirmation [3]
Portal ->> ClientTemplate: Redirect with status [4]
deactivate Portal
ClientTemplate ->> HelseId: Request access token for Selvbetjening API (using client id and key) [5]
activate HelseId
HelseId -->> ClientTemplate: access token
deactivate HelseId
ClientTemplate ->> API: Get status (using access token) [6]
activate API
API -->> ClientTemplate: Status
deactivate API
- Create a client draft using the API
- Direct the end user to the confirmation page at selvbetjening.nhn.no in a browser
- The end user confirms the client
- The browser redirects to your local http server
- With a successful status, you can request access tokens from HelseID
- Check the status of the client's access to the specified scopes
Creating a client draft
An API key is required to create client drafts, and is generated from the "automation" tab on the client template page.
The API key can be distributed with the client system installations, and is only used for creating client drafts. After the HelseID client is created, the system installation must use this client for further API calls.
Generate a key pair and POST to the
/client-drafts
endpoint with the API key as a header to create a new draft:
POST /v1/client-drafts HTTP/1.1
Host: api.selvbetjening.nhn.no
Api-Key: D-J1mmTqICvFRK3sgBZVKCqcBXq6NFhSZPjgPOgCxO8
Content-Type: application/json
Accept: application/json
{
"organizationNumber": "942110464",
"apiScopes": [
"nhn:selvbetjening/client",
"nhn:kjernejournal/api"
],
"publicJwk": "{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"fHKI4bI_4yG1x7wfSbcS33N0NWDz0lkSELN1LTaVxtE\",\"y\":\"4JKkagfmenlwCqhhQzir2n_5vn4HmULwLc3bQCJBS60\",\"kid\":\"M2WOBEsDcuWbHUAewajNnMgb-qElkpRhcvBZj6mlmnE\",\"use\":\"sig\",\"alg\":\"ES512\"}",
"postClientConfirmationRedirectUri": "http://localhost:8080/client-confirm"
}// KeyGenerator from https://github.com/NorskHelsenett/Selvbetjening.Samples
var jwk = KeyGenerator.GenerateRsaJwk();
// Save jwk.PublicAndPrivateValue to a secure location,
// such as a key vault
var clientDraft = new {
OrganizationNumber = "942110464",
PublicJwk = jwk.PublicValue,
ApiScopes = new []{"nhn:selvbetjening/client", "nhn:kjernejournal/api"},
PostClientConfirmationRedirectUri = "http://localhost:8080/client-confirm"
};
var client = new HttpClient();
client.DefaultRequestHeaders.Add(
"Api-Key",
"D-J1mmTqICvFRK3sgBZVKCqcBXq6NFhSZPjgPOgCxO8"
);
var response = await client.PostAsJsonAsync(
"https://api.selvbetjening.test.nhn.no/v1/client-drafts",
clientDraft
);
var body = await response.Content.ReadFromJsonAsync<ResponseModel>();
var clientId = body.ClientId;
record ResponseModel(string ClientId);A successful response includes the client id for the new draft:
{
"clientId": "4095f02f-008e-4413-98ef-5c040eb28b29"
}User confirmation
The client must be confirmed by a user representing the organization number specified in the draft. This is done by opening a URL to Selvbetjening in a browser where the user will sign in and confirm the client.
The client system must listen for HTTP requests to postClientConfirmationRedirectUri (from the client draft), which Selvbetjening
redirects to after the user has confirmed the client.
The client system must then open Selvbetjening in a browser using this URL template:
https://selvbetjening(.test).nhn.no/confirm-client/{clientId}.
When the client has been confirmed, the client system
will receive a redirect to postClientConfirmationRedirectUri with the query
parameter status.
See postClientConfirmationRedirectUri description for possible statuses.
var confirmationUri = "https://selvbetjening.nhn.no/confirm-client/4095f02f-008e-4413-98ef-5c040eb28b29";
var postClientConfirmationRedirectUri = "http://localhost:8080/client-confirm";
// Open confirmation URI in browser and listen for the confirmation redirect
var browserOptions = new BrowserOptions(
startUrl: confirmationUri,
endUrl: postClientConfirmationRedirectUri
);
// SystemBrowserRunner from https://github.com/NorskHelsenett/Selvbetjening.Samples
using var browserRunner = new SystemBrowserRunner(
htmlTitle: "My Application",
htmlBody: "Return to your application"
);
var result = await browserRunner.InvokeAsync(browserOptions, default);
var queryString = result.Response;
var confirmationParameters = HttpUtility.ParseQueryString(queryString);
var isSuccess = confirmationParameters["status"] == "Success";On success, the client is ready for use within 20 seconds (HelseID's cache must be updated).
Checking access status
Check the access of the requested scopes by using the /client endpoint.
This endpoint requires your newly created client to request a HelseID access token with the scope
nhn:selvbetjening/client.
See the client implementation guide for how to integrate with HelseID.
GET /v1/client/ HTTP/1.1
Host: api.selvbetjening.nhn.no
Authorization: DPoP <access_token>
DPoP: <dpop_proof>
Accept: application/jsonvar requestMessage = new HttpRequestMessage(
HttpMethod.Get,
"https://api.selvbetjening.test.nhn.no/v1/client/"
);
// See the full sample for how to get access token and DPoP proof:
// https://github.com/NorskHelsenett/Selvbetjening.Samples
requestMessage.Headers.Authorization = new("DPoP", "<your_access_token>");
requestMessage.Headers.Add("DPoP", "<your_dpop_proof>");
using var client = new HttpClient();
var response = await client.SendAsync(requestMessage);
var responseData = await response.Content.ReadFromJsonAsync<ResponseModel>();
var scopesAllOk = responseData!.ApiScopes.All(s => s.Status == "ok");
// See endpoint docs for all properties
record ResponseModel(ApiScope[] ApiScopes);
record ApiScope(string Scope, string Status);The response will include status for each API scope and other client details:
{
"apiScopes": [
{
"scope": "nhn:selvbetjening/client",
"status": "ok"
},
{
"scope": "nhn:kjernejournal/api",
"status": "ok"
}
]
}If the status looks good, you are ready to request access tokens for other APIs.
Key rotation
Client keys expire after 30 days. Regular key rotation is therefore required to keep your client working.
Rotate the key in good time before expiration to avoid disruptions, e.g. 15 days before expiration. The previous key will still be valid for 14 days when rotated.
Rotation is accomplished using the /client-secret endpoint:
POST /v1/client-secret HTTP/1.1
Host: api.selvbetjening.nhn.no
Authorization: DPoP <access_token>
DPoP: <dpop_proof>
Content-Type: application/json
Accept: application/json
{
"kty": "EC",
"crv": "P-256",
"x": "fHKI4bI_4yG1x7wfSbcS33N0NWDz0lkSELN1LTaVxtE",
"y": "4JKkagfmenlwCqhhQzir2n_5vn4HmULwLc3bQCJBS60",
"kid": "M2WOBEsDcuWbHUAewajNnMgb-qElkpRhcvBZj6mlmnE",
"use": "sig",
"alg": "ES512"
}// KeyGenerator from https://github.com/NorskHelsenett/Selvbetjening.Samples
var newJwk = KeyGenerator.GenerateRsaJwk();
// Save jwk.PublicAndPrivateValue to a secure location,
// such as a key vault
var requestMessage = new HttpRequestMessage(
HttpMethod.Post,
"https://api.selvbetjening.test.nhn.no/v1/client-secret"
);
// See the full sample for how to get access token and DPoP proof:
// https://github.com/NorskHelsenett/Selvbetjening.Samples
requestMessage.Headers.Authorization = new("DPoP", "<your_access_token>");
requestMessage.Headers.Add("DPoP", "<your_dpop_proof>");
requestMessage.Content = JsonContent.Create(newJwk.PublicValue);
using var client = new HttpClient();
var response = await client.SendAsync(requestMessage);
var responseData = await response.Content.ReadFromJsonAsync<ResponseModel>();
var expiration = responseData.Expiration;
record ResponseModel(DateTime Expiration);The expiration date for the new key is returned:
{
"expiration": "2025-05-21T00:00:00.00Z"
}Handling expired client keys
If an application is not used for long period of time, the public key of the client secret will not be automatically updated by the software, and might expire.
To handle this, a user with access to the client should do the following:
- Generate a new keypair
- Log into Selvbetjening and upload the new public key for the client
- Make the application use the new private key
End users of the application might need assistance from the software vendor in order to perform this "revival" of the HelseID integration.
Please note: As long as the application is used regularly, and the public key is updated, the problem of key expiration will not occur.