Guide API documentation Community Applications
Introduction
Authentication
Overview Server application Web Auth SPA, mobile and native Using Postman with Unimicro API
Using the API
Guides
Payroll
Legal

Server application

Server applications are able to authenticate with the Unimicro APIs through a certificate based client credential flow.

They may act on behalf of companies they've been given access to without human interaction.

This article shows how to authenticate as a C# .NET server client.

Prerequisites
In this article we assume you've already signed up, created an application and set up a server client in the application's settings page. You should have a Client ID as well as a certificate for your application.

Create a client token

In order to create a client token we start by loading our certificate. We then use this certificate to sign a JWT access token with our Client ID and the identity server's token endpoint.

// Audience should be set to the identity server's token endpoint, e.g. https://test-login.unimicro.no/connect/token for our test environment

private static string CreateClientToken(string clientId, string audience)
{
    var certificate = new X509Certificate2(@"path\to\Cert.p12", "certificate password");
    var now = DateTime.UtcNow;

    var securityKey = new X509SecurityKey(certificate);
    var signingCredentials = new SigningCredentials(
        securityKey,
        SecurityAlgorithms.RsaSha256
    );

    var token = new JwtSecurityToken(
        clientId,
        audience,
        new List<Claim>()
        {
            new Claim("jti", Guid.NewGuid().ToString()),
            new Claim(JwtClaimTypes.Subject, clientId),
            new Claim(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(), ClaimValueTypes.Integer64)
        },
        now,
        now.AddMinutes(1),
        signingCredentials
    );

    var tokenHandler = new JwtSecurityTokenHandler();
    return tokenHandler.WriteToken(token);
}

The resulting token should contain the following fields in it's payload.

{
  "jti": <guid>,
  "sub": <clientid>,
  "iat": 1592557940,
  "nbf": 1592557940,
  "exp": 1592558000,
  "iss": <clientid>,
  "aud": "https://test-login.unimicro.no/connect/token"
}

Request access token

Once you have your client token you can use that to request an access token.

static async Task<TokenResponse> RequestTokenAsync()
{
    var client = new HttpClient();

    var disco = await client.GetDiscoveryDocumentAsync("https://test-login.unimicro.no");
    if (disco.IsError) throw new Exception(disco.Error);

    var clientToken = CreateClientToken("client-id", disco.TokenEndpoint);

    var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
    {
        Address = disco.TokenEndpoint,
        Scope = "Scope1 scope2",

        ClientAssertion =
        {
            Type = OidcConstants.ClientAssertionTypes.JwtBearer,
            Value = clientToken
        }
    });

    if (response.IsError) throw new Exception(response.Error);
    return response;
}

The request to connect/token that was generated should look something like this.

POST https://test-login.unimicro.no/connect/token

Body (application/x-www-form-urlencoded)

{
    "client_id": "<clientId>",
    "scope": "AppFramework",
    "grant_type": "client_credentials",
    "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
    "client_assertion": "<local generated jwt-token>"
  }

Send a request to the API

Once you have your access token you can use it to communicate with the Unimicro APIs. Let's fetch the CompanySettings entity.

static async Task CallServiceAsync(string token)
{
    var baseAddress = "https://test.unimicro.no/";

    var client = new HttpClient
    {
        BaseAddress = new Uri(baseAddress)
    };

    client.SetBearerToken(token);

    try
    {
        var response = client.GetStringAsync("https://test.unimicro.no/api/init/companies").Result;
        Console.WriteLine("Result: " + JArray.Parse(response));

        var companies = JsonConvert.DeserializeObject<List<Company>>(response);
        client.DefaultRequestHeaders.Add("CompanyKey", companies[0].Key);

        var companyResponse = client.GetStringAsync("https://test.unimicro.no/api/biz/companysettings").Result;

        Console.WriteLine("CompanySettings: " + JArray.Parse(companyResponse));
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception: " + ex.Message + " \n stack " + ex.StackTrace);
    }
}

References

The following references has been used in these examples

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using IdentityModel;
using IdentityModel.Client;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using NodaTime;