### Production Setup with Key Identifier Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfigurationFactory.md Shows how to create a production configuration using RSA private and public keys, along with a key identifier. This setup is for production environments. ```csharp var rsaPrivateKey = RSA.Create(); var rsaPublicKey = RSA.Create(); // ... initialize keys from storage var config = MaskinportenClientConfigurationFactory.CreateProdConfiguration( issuer: "my-prod-issuer", privateKey: rsaPrivateKey, publicKey: rsaPublicKey, keyIdentifier: "prod-key-2024", numberOfSecondsLeftBeforeExpire: 15, consumerOrg: "987654321"); var client = new MaskinportenClient(config); ``` -------------------------------- ### GetToken Usage Example Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/ITokenCache.md Example demonstrating how to use the GetToken method with a token fetching factory function. Ensure necessary using directives are present. ```csharp using Ks.Fiks.Maskinporten.Client.Cache; using KS.Fiks.Maskinporten.Client; ITokenCache cache = new TokenCache(); var request = new TokenRequest { Scopes = "ks:fiks" }; // Invoke GetToken with a factory function var token = await cache.GetToken( request, async () => { // Factory: fetch from Maskinporten var response = await maskinportenService.FetchToken(); return new MaskinportenToken(response.Token, response.ExpiresIn); }); Console.WriteLine(token.Token); ``` -------------------------------- ### Dependency Injection Setup Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/README.md Register the Maskinporten client as a singleton service using dependency injection. This example shows how to configure the client for production within the DI container. ```csharp services.AddSingleton(sp => { var config = MaskinportenClientConfigurationFactory.CreateProdConfiguration( issuer: GetIssuerId(), certificate: LoadCertificate()); return new MaskinportenClient(config); }); ``` -------------------------------- ### Install KS.Fiks.Maskinporten.Client Package Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/README.md Use the dotnet CLI to add the Maskinporten client package to your project. ```bash dotnet add package KS.Fiks.Maskinporten.Client ``` -------------------------------- ### Simple Setup with Certificate (Test) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfigurationFactory.md Demonstrates how to create a test configuration using an X509 certificate and initialize a MaskinportenClient. This is suitable for testing integrations. ```csharp var cert = new X509Certificate2("test-cert.pfx", "password"); var config = MaskinportenClientConfigurationFactory.CreateTestConfiguration( issuer: "my-test-issuer", certificate: cert); var client = new MaskinportenClient(config); var token = await client.GetAccessToken("ks:fiks"); ``` -------------------------------- ### Minimal Request Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequest.md Example of creating a minimal TokenRequest with only the required scopes. ```APIDOC ## Minimal Request (Scopes Only) ### Description Constructs a `TokenRequest` with the minimum required `Scopes`. ### Usage ```csharp var request = new TokenRequest { Scopes = "ks:fiks" }; var token = await client.GetAccessToken(request); ``` ``` -------------------------------- ### Dependency Injection Configuration Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/ITokenCache.md Example of configuring dependency injection to use a custom ITokenCache implementation. This replaces the default caching behavior. ```csharp using Microsoft.Extensions.DependencyInjection; using Ks.Fiks.Maskinporten.Client.Cache; services.AddSingleton(sp => { return new CustomTokenCache(); // Custom implementation }); ``` -------------------------------- ### Create TokenRequest with Scopes and ConsumerOrg Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequest.md Example of creating a TokenRequest with required scopes and a consumer organization number for delegated access. ```csharp var request = new TokenRequest { Scopes = "ks:fiks", ConsumerOrg = "123456789" }; var token = await client.GetAccessToken(request); ``` -------------------------------- ### Delegation Request Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequest.md Example of creating a TokenRequest for delegation, including the consumer organization. ```APIDOC ## Delegation Request ### Description Constructs a `TokenRequest` for delegation, specifying the `Scopes` and `ConsumerOrg`. ### Usage ```csharp var request = new TokenRequest { Scopes = "ks:fiks", ConsumerOrg = "123456789" }; var token = await client.GetAccessToken(request); ``` ``` -------------------------------- ### Mock IMaskinportenClient for Unit Testing Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Provides an example of creating a mock implementation of IMaskinportenClient using Moq for unit testing purposes. This allows simulating token retrieval without actual network calls. ```csharp using Moq; var mockClient = new Mock(); mockClient .Setup(c => c.GetAccessToken(It.IsAny())) .ReturnsAsync(new MaskinportenToken("fake-jwt-token", 3600)); var systemUnderTest = new MyService(mockClient.Object); var result = await systemUnderTest.GetToken(); Assert.AreEqual("fake-jwt-token", result); ``` -------------------------------- ### MaskinportenClientConfigurationFactory Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/MANIFEST.txt Factory class for creating `MaskinportenClientConfiguration` instances, simplifying setup for different environments. ```APIDOC ## MaskinportenClientConfigurationFactory ### Description The `MaskinportenClientConfigurationFactory` provides convenient methods to create `MaskinportenClientConfiguration` objects, pre-configured for specific environments (like test or production) and common scenarios. ### Methods - **CreateTestConfiguration(...)**: Creates a configuration for the test environment. - **CreateProductionConfiguration(...)**: Creates a configuration for the production environment. ### Usage Use the factory methods to obtain a configuration object, then pass it to the `MaskinportenClient` constructor. ``` -------------------------------- ### Get Basic Access Token Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/README.md Obtain a basic access token for a given scope. The token is a JWT string. ```csharp var token = await client.GetAccessToken("ks:fiks"); Console.WriteLine(token.Token); // JWT string ``` -------------------------------- ### Get Maskinporten Access Token with Correct Scope Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/errors.md Demonstrates the correct way to request an access token by providing the required scope. Incorrect scope usage can lead to 'Missing Scope' errors. ```csharp // ❌ WRONG: No scope var token = await client.GetAccessToken(""); // ✅ CORRECT: Provide scope var token = await client.GetAccessToken("ks:fiks"); ``` -------------------------------- ### Initialize JwtRequestTokenGenerator with RSA Keys Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/JwtRequestTokenGenerator.md Use this constructor when you have separate RSA public and private key objects. This is useful for managing keys independently or in multi-key setups. An optional key identifier can be provided for the JWT 'kid' header. ```csharp using System.Security.Cryptography; using Ks.Fiks.Maskinporten.Client.Jwt; var publicKey = RSA.Create(); var privateKey = RSA.Create(); // Load keys from storage... var generator = new JwtRequestTokenGenerator(publicKey, privateKey); // With key identifier for multi-key setups var generator2 = new JwtRequestTokenGenerator( publicKey, privateKey, keyIdentifier: "backup-key"); ``` -------------------------------- ### Get Access Token with Caching Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/README.md Demonstrates how token caching works. The first request hits the Maskinporten endpoint, while subsequent requests for the same parameters return a cached token if it's not expired. ```csharp // First request - hits Maskinporten endpoint var token1 = await client.GetAccessToken("ks:fiks"); // Subsequent requests - returns cached token (if not expired) var token2 = await client.GetAccessToken("ks:fiks"); // token1.Token == token2.Token ``` -------------------------------- ### Inject IMaskinportenClient and Get Access Token Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Illustrates injecting IMaskinportenClient into a service and using it to retrieve an access token for a specific scope. ```csharp public class MyService { private readonly IMaskinportenClient _maskinportenClient; public MyService(IMaskinportenClient maskinportenClient) { _maskinportenClient = maskinportenClient; } public async Task GetToken() { var token = await _maskinportenClient.GetAccessToken("ks:fiks"); return token.Token; } } ``` -------------------------------- ### TokenRequest Equality Check Example Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequest.md Demonstrates how to check for equality between two TokenRequest objects. Two requests are considered equal if all their properties (Scopes, ConsumerOrg, OnBehalfOf, Audience, Pid) are identical. This is useful for caching tokens based on unique request parameters. ```csharp var req1 = new TokenRequest { Scopes = "ks:fiks", ConsumerOrg = "123456789" }; var req2 = new TokenRequest { Scopes = "ks:fiks", ConsumerOrg = "123456789" }; var req3 = new TokenRequest { Scopes = "ks:fiks" }; Console.WriteLine(req1.Equals(req2)); // true (same properties) Console.WriteLine(req1.Equals(req3)); // false (different ConsumerOrg) ``` -------------------------------- ### Get Access Token with Full Control Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClient.md Use this method when you need to specify all parameters for the token request, including scopes, consumer organization, audience, and on-behalf-of information. Valid tokens are cached to avoid redundant requests. ```csharp var tokenRequest = new TokenRequest { Scopes = "ks:fiks", ConsumerOrg = "123456789", Audience = "https://some-api.example.com" }; var token = await client.GetAccessToken(tokenRequest); Console.WriteLine(token.Token); // JWT string ``` -------------------------------- ### Get Access Token with Scopes (string) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Obtains an access token for a space-separated scope string. Example: "ks:fiks other:scope". ```csharp Task GetAccessToken(string scopes) ``` -------------------------------- ### Create Test and Prod Configurations Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/README.md Use factory methods to create configurations for TEST and PROD environments. The `CreateVer2Configuration` method is deprecated. ```csharp // For TEST var maskinportenConfigTest = MaskinportenClientConfigurationFactory.CreateTestConfiguration("test_issuer", testCertificate); // For PROD var maskinportenConfigProd = MaskinportenClientConfigurationFactory.CreateProdConfiguration("prod_issuer", certificate); // DEPRECATED - For TEST (ver2) var maskinportenConfigVer2 = MaskinportenClientConfigurationFactory.CreateVer2Configuration("ver2_issuer", testCertificate); ``` -------------------------------- ### With Personal Identifier Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequest.md Example of creating a TokenRequest that includes a personal identifier. ```APIDOC ## With Personal Identifier ### Description Constructs a `TokenRequest` including a personal identifier (`Pid`) along with `Scopes` and `ConsumerOrg`. ### Usage ```csharp var request = new TokenRequest { Scopes = "ks:fiks", ConsumerOrg = "123456789", Pid = "12345678901" }; var token = await client.GetAccessToken(request); ``` ``` -------------------------------- ### Basic Maskinporten Client Usage Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/README.md Demonstrates how to load a certificate, create a test configuration, instantiate the Maskinporten client, and retrieve an access token. The obtained token can then be used in HTTP requests. ```csharp using System.Security.Cryptography.X509Certificates; using Ks.Fiks.Maskinporten.Client; // Load certificate var certificate = new X509Certificate2("cert.pfx", "password"); // Create configuration for test environment var config = MaskinportenClientConfigurationFactory.CreateTestConfiguration( issuer: "my-integration-id", certificate: certificate); // Create client var client = new MaskinportenClient(config); // Get access token var token = await client.GetAccessToken("ks:fiks"); // Use token in HTTP requests var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/data"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token); var response = await httpClient.SendAsync(request); ``` -------------------------------- ### Audience-Restricted Delegation Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequest.md Example of creating a TokenRequest for audience-restricted delegation, including the audience. ```APIDOC ## Audience-Restricted Delegation ### Description Constructs a `TokenRequest` for audience-restricted delegation, specifying `Scopes`, `ConsumerOrg`, and `Audience`. ### Usage ```csharp var request = new TokenRequest { Scopes = "ks:fiks", ConsumerOrg = "123456789", Audience = "https://api.example.com" }; var token = await client.GetAccessToken(request); ``` ``` -------------------------------- ### Create Production Environment Configuration using Factory Method Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/configuration.md Use the factory method to create a configuration for the production environment. Requires an issuer ID and a production certificate. ```csharp var config = MaskinportenClientConfigurationFactory.CreateProdConfiguration( issuer: "prod-issuer-id", certificate: productionCertificate); ``` -------------------------------- ### Initialize MaskinportenClient with Certificate Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClient.md Demonstrates how to initialize the MaskinportenClient using a PFX certificate for authentication. Ensure the certificate path and password are correct. ```csharp using System.Security.Cryptography.X509Certificates; using Ks.Fiks.Maskinporten.Client; // Load certificate var certificate = new X509Certificate2("path/to/certificate.pfx", "password"); // Create configuration for test environment var config = MaskinportenClientConfigurationFactory.CreateTestConfiguration( issuer: "my-issuer", certificate: certificate); // Create client var client = new MaskinportenClient(config); ``` -------------------------------- ### Create Test Environment Configuration using Factory Method Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/configuration.md Use the factory method to create a configuration for the test environment. Requires an issuer ID and a test certificate. ```csharp var config = MaskinportenClientConfigurationFactory.CreateTestConfiguration( issuer: "test-issuer-id", certificate: testCertificate); ``` -------------------------------- ### Token Property Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenToken.md Gets the JWT access token string, which is used in HTTP Authorization headers. ```APIDOC ## Token Property ### Description Gets the JWT access token string. This is the value to pass in HTTP Authorization headers as a Bearer token. ### Property Signature ```csharp public string Token { get; } ``` ### Type `string` (read-only) ### Example ```csharp var token = await client.GetAccessToken("ks:fiks"); var httpClient = new HttpClient(); using (var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/data")) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token); var response = await httpClient.SendAsync(request); } ``` ``` -------------------------------- ### Load and Configure Client from appsettings.json Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/configuration.md Load configuration values from `appsettings.json`, including certificate path and password, to create a production configuration for the Maskinporten client. Ensure the certificate file exists at the specified path. ```csharp var issuer = configuration["MaskinportenClient:Issuer"]; var refreshSeconds = int.Parse(configuration["MaskinportenClient:TokenRefreshSeconds"]); var certPath = configuration["MaskinportenClient:CertificatePath"]; var certPassword = configuration["MaskinportenClient:CertificatePassword"]; var certificate = new X509Certificate2(certPath, certPassword); var config = MaskinportenClientConfigurationFactory.CreateProdConfiguration( issuer: issuer, certificate: certificate, numberOfSecondsLeftBeforeExpire: refreshSeconds, consumerOrg: configuration["MaskinportenClient:DefaultConsumerOrg"]); services.AddSingleton(new MaskinportenClient(config)); ``` -------------------------------- ### Configure Client for Production Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/README.md Create a production-ready configuration for the Maskinporten client using a factory method. Requires an issuer ID and a production certificate. ```csharp var config = MaskinportenClientConfigurationFactory.CreateProdConfiguration( issuer: "prod-integration-id", certificate: productionCertificate); var client = new MaskinportenClient(config); ``` -------------------------------- ### Using TokenRequestBuilder Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequestBuilder.md Demonstrates how to use the TokenRequestBuilder to set scopes and consumer organization, then build the TokenRequest. ```APIDOC ## Using Builder ```csharp var request = new TokenRequestBuilder() .WithScopes("ks:fiks") .WithConsumerOrg("123456789") .Build(); ``` ``` -------------------------------- ### Build Token Request with All Parameters Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequestBuilder.md Create a comprehensive token request including multiple scopes, consumer organization, audience, and a personal identification number. Validation of these parameters occurs during token acquisition. ```csharp using KS.Fiks.Maskinporten.Client.Builder; var request = new TokenRequestBuilder() .WithScopes(new[] { "ks:fiks", "other:scope" }) .WithConsumerOrg("123456789") .WithAudience("https://api.example.com") .WithPid("12345678901") .Build(); var token = await client.GetAccessToken(request); ``` -------------------------------- ### Get Access Token Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/README.md Retrieve an access token for a specified scope using the MaskinportenClient. Ensure the scope is correctly defined. ```csharp var scope = "ks:fiks"; // Scope for access token var accessToken = await maskinportenClient.GetAccessToken(scope); ``` -------------------------------- ### Initialize MaskinportenClientConfiguration with Certificate Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfiguration.md Use this constructor to initialize the configuration with an X.509 certificate for authentication. Ensure the certificate contains both public and private keys. The keyIdentifier and consumerOrg are optional parameters. ```csharp using System.Security.Cryptography.X509Certificates; using Ks.Fiks.Maskinporten.Client; var certificate = new X509Certificate2("cert.pfx", "password"); var config = new MaskinportenClientConfiguration( audience: "https://test.maskinporten.no/", tokenEndpoint: "https://test.maskinporten.no/token", issuer: "my-integration-id", numberOfSecondsLeftBeforeExpire: 10, certificate: certificate, keyIdentifier: "key-1", consumerOrg: "987654321"); var client = new MaskinportenClient(config); ``` -------------------------------- ### Instantiate MaskinportenClient with Test Configuration Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Demonstrates how to create an instance of MaskinportenClient using a test configuration. Requires a valid issuer and certificate. ```csharp using Ks.Fiks.Maskinporten.Client; var config = MaskinportenClientConfigurationFactory.CreateTestConfiguration( issuer: "my-issuer", certificate: cert); IMaskinportenClient client = new MaskinportenClient(config); ``` -------------------------------- ### CreateVer2Configuration (Obsolete) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfigurationFactory.md Creates a configuration for the deprecated Maskinporten ver2 test environment. Use `CreateTestConfiguration()` instead. ```csharp public static MaskinportenClientConfiguration CreateVer2Configuration( string issuer, X509Certificate2 certificate = null, RSA privateKey = null, RSA publicKey = null, string keyIdentifier = null, int numberOfSecondsLeftBeforeExpire = DEFAULT_NUMBER_SECONDS_LEFT, string consumerOrg = null) ``` -------------------------------- ### Get on behalf of access token Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/README.md Retrieves an on-behalf-of access token. Note that this feature has limited use cases and is planned for removal. ```c# var scope = "ks:fiks"; // Scope for access token var consumerOrgNo = ...; // Official 9 digit organization number for an organization that has delegated access to you in ALTINN var accessToken = await maskinportenClient.GetOnBehalfOfAccessToken(consumerOrgNo, scope); ``` -------------------------------- ### Get delegated access audience-restricted token Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/README.md Retrieves an access token restricted to a specific audience and scope for an organization that has delegated access. ```c# var audience = "https://some/api"; // Audience for access token var scope = "ks:fiks"; // Scope for access token var consumerOrgNo = ...; // Official 9 digit organization number for an organization that has delegated access to you in ALTINN var accessToken = await maskinportenClient.GetDelegatedAccessTokenForAudience(consumerOrgNo, audience, scope); ``` -------------------------------- ### Load Certificate from PFX File Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/configuration.md Use this method to load a certificate from a PFX file, which typically contains both the public and private keys. Requires the file path and password. ```csharp var certificate = new X509Certificate2("path/to/certificate.pfx", "password"); var config = MaskinportenClientConfigurationFactory.CreateTestConfiguration( issuer: "my-issuer", certificate: certificate); ``` -------------------------------- ### Get Audience-Restricted Token Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/README.md Obtain a delegated access token restricted to a specific audience and scope. This ensures the token can only be used with the intended API. ```csharp var token = await client.GetDelegatedAccessTokenForAudience( consumerOrg: "123456789", audience: "https://api.example.com", scopes: "ks:fiks"); ``` -------------------------------- ### Create Production Configuration Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfigurationFactory.md Use this method to create a configuration for the Maskinporten production environment. Audience and token endpoint are automatically set to production values. Provide the issuer and optionally a certificate or private/public key. ```csharp public static MaskinportenClientConfiguration CreateProdConfiguration( string issuer, X509Certificate2 certificate = null, RSA privateKey = null, RSA publicKey = null, string keyIdentifier = null, int numberOfSecondsLeftBeforeExpire = DEFAULT_NUMBER_SECONDS_LEFT, string consumerOrg = null) ``` ```csharp using System.Security.Cryptography.X509Certificates; using Ks.Fiks.Maskinporten.Client; var certificate = new X509Certificate2("prod-cert.pfx", "password"); var config = MaskinportenClientConfigurationFactory.CreateProdConfiguration( issuer: "prod-issuer-id", certificate: certificate, keyIdentifier: "primary-key"); var client = new MaskinportenClient(config); ``` -------------------------------- ### Instantiate JwtRequestTokenGenerator Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IJwtRequestTokenGenerator.md Demonstrates how to create an instance of JwtRequestTokenGenerator using either an X.509 certificate or an RSA key pair. Choose the method that matches your credential management. ```csharp using System.Security.Cryptography.X509Certificates; using Ks.Fiks.Maskinporten.Client.Jwt; // With certificate var certificate = new X509Certificate2("cert.pfx", "password"); IJwtRequestTokenGenerator generator = new JwtRequestTokenGenerator(certificate); // With RSA key pair var privateKey = RSA.Create(); var publicKey = RSA.Create(); IJwtRequestTokenGenerator generator2 = new JwtRequestTokenGenerator(publicKey, privateKey); ``` -------------------------------- ### Get Access Token with Scopes (IEnumerable) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Obtains an access token for a collection of scopes. The client internally joins the scope strings with spaces. ```csharp Task GetAccessToken(IEnumerable scopes) ``` -------------------------------- ### Get Delegated Access Token Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/README.md Retrieve a delegated access token for a specific consumer organization and scope. Refer to DigDir documentation for more details on delegation. ```csharp var scope = "ks:fiks"; // Scope for access token var consumerOrgNo = ...; // Official 9 digit organization number for an organization that has delegated access to you in ALTINN var accessToken = await maskinportenClient.GetDelegatedAccessToken(consumerOrgNo, scope); ``` -------------------------------- ### Initialize TokenRequestBuilder Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequestBuilder.md Initializes a new TokenRequestBuilder with an empty TokenRequest. All methods are chainable and return the same builder instance. ```csharp public TokenRequestBuilder() ``` -------------------------------- ### Get On-Behalf-Of Access Token with String Scopes Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClient.md Obtains an on-behalf-of access token with space-separated scopes. Use this overload when scopes are provided as a single space-separated string. ```csharp public Task GetOnBehalfOfAccessToken( string consumerOrg, string scopes) ``` ```csharp var token = await client.GetOnBehalfOfAccessToken( consumerOrg: "123456789", scopes: "ks:fiks"); ``` -------------------------------- ### Get Access Token with TokenRequest Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Obtains an access token using a fully-configured TokenRequest object. Ensure all parameters within TokenRequest are correctly set before calling this method. ```csharp Task GetAccessToken(TokenRequest tokenRequest) ``` -------------------------------- ### CreateVer2Configuration Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfigurationFactory.md Creates a configuration for the deprecated Maskinporten ver2 test environment. Use `CreateTestConfiguration()` instead. ```APIDOC ## CreateVer2Configuration(string, X509Certificate2, RSA, RSA, string, int, string) ### Description Creates a configuration for the deprecated Maskinporten ver2 test environment. Use `CreateTestConfiguration()` instead. ### Method Signature ```csharp [Obsolete("VER2 is deprecated, use CreateTestConfiguration instead")] public static MaskinportenClientConfiguration CreateVer2Configuration( string issuer, X509Certificate2 certificate = null, RSA privateKey = null, RSA publicKey = null, string keyIdentifier = null, int numberOfSecondsLeftBeforeExpire = DEFAULT_NUMBER_SECONDS_LEFT, string consumerOrg = null) ``` ### Parameters #### Path Parameters * **issuer** (string) - Required - Integration identifier * **certificate** (X509Certificate2) - Optional - X.509 certificate * **privateKey** (RSA) - Optional - RSA private key * **publicKey** (RSA) - Optional - RSA public key * **keyIdentifier** (string) - Optional - Optional key identifier * **numberOfSecondsLeftBeforeExpire** (int) - Optional - Token refresh threshold (Default: 10) * **consumerOrg** (string) - Optional - Optional organization number ### Returns `MaskinportenClientConfiguration` - A configuration with deprecated endpoints: - **Audience:** `https://ver2.maskinporten.no/` - **Token Endpoint:** `https://ver2.maskinporten.no/token` ### Deprecation Notice This method is obsolete and will be removed in a future version. Migrate to `CreateTestConfiguration()` immediately. ``` -------------------------------- ### Get Delegated Access Token with String Scopes Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClient.md Obtains an audience-restricted delegated access token with space-separated scopes. Use this overload when scopes are provided as a single space-separated string. ```csharp public Task GetDelegatedAccessTokenForAudience( string consumerOrg, string audience, string scopes) ``` ```csharp var token = await client.GetDelegatedAccessTokenForAudience( consumerOrg: "123456789", audience: "https://api.example.com", scopes: "ks:fiks"); ``` -------------------------------- ### Create VER2 Test Environment Configuration (Deprecated) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/configuration.md Use this factory method for the deprecated VER2 test environment. Migration to CreateTestConfiguration is recommended. ```csharp [Obsolete("VER2 is deprecated, use CreateTestConfiguration instead")] var config = MaskinportenClientConfigurationFactory.CreateVer2Configuration( issuer: "ver2-issuer-id", certificate: testCertificate); ``` -------------------------------- ### Create Test Configuration Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfigurationFactory.md Use this method to create a configuration for the Maskinporten test environment. Audience and token endpoint are automatically set to test values. Ensure you provide the issuer and optionally a certificate or private/public key. ```csharp public static MaskinportenClientConfiguration CreateTestConfiguration( string issuer, X509Certificate2 certificate = null, RSA privateKey = null, RSA publicKey = null, string keyIdentifier = null, int numberOfSecondsLeftBeforeExpire = DEFAULT_NUMBER_SECONDS_LEFT, string consumerOrg = null) ``` ```csharp using System.Security.Cryptography.X509Certificates; using Ks.Fiks.Maskinporten.Client; var certificate = new X509Certificate2("test-cert.pfx", "password"); var config = MaskinportenClientConfigurationFactory.CreateTestConfiguration( issuer: "test-issuer-id", certificate: certificate); var client = new MaskinportenClient(config); ``` -------------------------------- ### Get Token Hash Code - C# Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenToken.md Generates a hash code for a MaskinportenToken based on its JWT string. This enables the token to be used in hash-based collections like dictionaries and hash sets. ```csharp public override int GetHashCode() ``` -------------------------------- ### Register IMaskinportenClient with Dependency Injection Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Shows how to register the IMaskinportenClient interface with a DI container for production use. Ensure the certificate is loaded correctly. ```csharp using Microsoft.Extensions.DependencyInjection; using Ks.Fiks.Maskinporten.Client; services.AddSingleton(sp => { var config = MaskinportenClientConfigurationFactory.CreateProdConfiguration( issuer: "my-issuer", certificate: LoadCertificate()); return new MaskinportenClient(config); }); ``` -------------------------------- ### Get On-Behalf-Of Access Token with Scopes (IEnumerable) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Obtains an on-behalf-of access token. This feature is deprecated and has limited use cases for Maskinporten integrations. It may be removed in future versions. ```csharp Task GetOnBehalfOfAccessToken( string consumerOrg, IEnumerable scopes) ``` -------------------------------- ### CreateProdConfiguration Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfigurationFactory.md Creates a configuration for the Maskinporten production environment. Audience and token endpoint are automatically set to production values. ```APIDOC ## CreateProdConfiguration(string issuer, X509Certificate2 certificate = null, RSA privateKey = null, RSA publicKey = null, string keyIdentifier = null, int numberOfSecondsLeftBeforeExpire = DEFAULT_NUMBER_SECONDS_LEFT, string consumerOrg = null) ### Description Creates a configuration for the Maskinporten production environment. Audience and token endpoint are automatically set to production values. ### Method Signature ```csharp public static MaskinportenClientConfiguration CreateProdConfiguration( string issuer, X509Certificate2 certificate = null, RSA privateKey = null, RSA publicKey = null, string keyIdentifier = null, int numberOfSecondsLeftBeforeExpire = DEFAULT_NUMBER_SECONDS_LEFT, string consumerOrg = null) ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | issuer | `string` | Yes | — | Integration identifier from DigDir | | certificate | `X509Certificate2` | No | `null` | X.509 certificate with private key | | privateKey | `RSA` | No | `null` | RSA private key (alternative to certificate) | | publicKey | `RSA` | No | `null` | RSA public key (alternative to certificate) | | keyIdentifier | `string` | No | `null` | Optional key identifier for `kid` JWT header | | numberOfSecondsLeftBeforeExpire | `int` | No | `10` | Seconds before token expiration to trigger refresh | | consumerOrg | `string` | No | `null` | Optional default organization number (9 digits) | ### Returns `MaskinportenClientConfiguration` — A configuration with: - **Audience:** `https://maskinporten.no/` - **Token Endpoint:** `https://maskinporten.no/token` ### Example ```csharp using System.Security.Cryptography.X509Certificates; using Ks.Fiks.Maskinporten.Client; var certificate = new X509Certificate2("prod-cert.pfx", "password"); var config = MaskinportenClientConfigurationFactory.CreateProdConfiguration( issuer: "prod-issuer-id", certificate: certificate, keyIdentifier: "primary-key"); var client = new MaskinportenClient(config); ``` ``` -------------------------------- ### Get On-Behalf-Of Access Token with Scopes (string) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Obtains an on-behalf-of access token using a space-separated scope string. This method is deprecated and has limited applicability, with potential removal in future versions. ```csharp Task GetOnBehalfOfAccessToken( string consumerOrg, string scopes) ``` -------------------------------- ### Get Delegated Access Token with Scopes (string) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Obtains a delegated access token for a specific organization using a space-separated scope string. Provide the consumer organization's 9-digit number. ```csharp Task GetDelegatedAccessToken( string consumerOrg, string scopes) ``` -------------------------------- ### Direct TokenRequest Initialization Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequestBuilder.md Shows an alternative method for creating a TokenRequest object directly, without using a builder. ```APIDOC ## Direct Object Initialization ```csharp var request = new TokenRequest { Scopes = "ks:fiks", ConsumerOrg = "123456789" }; ``` ``` -------------------------------- ### Create MaskinportenClientConfiguration with RSA Key Pair Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfiguration.md Use this snippet to create a configuration object when using an RSA key pair. The private and public keys need to be loaded from their respective formats (e.g., PEM, PKCS8). ```csharp var rsaPrivateKey = RSA.Create(); var rsaPublicKey = RSA.Create(); // ... load keys from PEM, PKCS8, or other format var config = new MaskinportenClientConfiguration( audience: "https://maskinporten.no/", tokenEndpoint: "https://maskinporten.no/token", issuer: "my-issuer", numberOfSecondsLeftBeforeExpire: 10, privateKey: rsaPrivateKey, publicKey: rsaPublicKey); ``` -------------------------------- ### Get Access Token Using TokenRequestBuilder Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/README.md Obtain an access token by building a `TokenRequest` object. This allows specifying scopes, consumer organization, on-behalf-of information, audience, and a personal identification number. ```csharp var tokenRequest = new TokenRequestBuilder() .WithScopes("ks:fiks") // Scope for access token .WithConsumerOrg("123456789") // Official 9 digit organization number for an organization that has delegated access to you in ALTINN .WithOnBehalfOf("123456789") // Official 9 digit organization number for an organization that has delegated access to you in ALTINN .WithAudience("https://some/api") // 'resource' claim in the JWT grant and 'aud' claim in the resulting access token .WithPid("12345678901") // Personal indentification number of the intended subject of the subsequent API calls .Build(); var accessToken = await maskinportenClient.GetAccessToken(tokenRequest); ``` -------------------------------- ### Create MaskinportenClient Instance Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/README.md Instantiate the MaskinportenClient with the provided configuration object. ```csharp var maskinportenClient = new MaskinportenClient(maskinportenConfig); ``` -------------------------------- ### Complete Test Environment Configuration Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/README.md Manually configure Maskinporten client settings for the test environment. Ensure all required parameters like audience, token endpoint, issuer, and certificate are provided. ```csharp var maskinportenConfig = new MaskinportenClientConfiguration( audience: @"https://test.maskinporten.no/", // Maskinporten audience path tokenEndpoint: @"https://test.maskinporten.no/token", // Maskinporten token path issuer: @"issuer", // Issuer name, heter nå Integrasjonens identifikator i selvbetjeningsløsningen til DigDir numberOfSecondsLeftBeforeExpire: 10, // The token will be refreshed 10 seconds before it expires certificate: /* virksomhetssertifikat as a X509Certificate2 */, privateKey: /* use together with public key if not using certificate parameter */, publicKey: /* use together with private key if not using certificate parameter */, keyIdentifier: /* optional value. Sets header kid */, consumerOrg: /* optional value. Sets header consumer_org */); ``` -------------------------------- ### Get Delegated Access Token with IEnumerable Scopes Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClient.md Obtains an audience-restricted delegated access token. The token is restricted to a specific API endpoint (audience) and can only be used with that API. Use this overload when scopes are provided as a collection. ```csharp public Task GetDelegatedAccessTokenForAudience( string consumerOrg, string audience, IEnumerable scopes) ``` ```csharp var token = await client.GetDelegatedAccessTokenForAudience( consumerOrg: "123456789", audience: "https://api.example.com", scopes: new[] { "ks:fiks" }); ``` -------------------------------- ### Get Delegated Access Token with Scopes (IEnumerable) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Obtains a delegated access token for a specific organization via ALTINN delegation. Requires the consumer organization's 9-digit number and a collection of scope strings. ```csharp Task GetDelegatedAccessToken( string consumerOrg, IEnumerable scopes) ``` -------------------------------- ### Basic Exception Handling for UnexpectedResponseException Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/UnexpectedResponseException.md Demonstrates how to catch and handle the UnexpectedResponseException when requesting an access token. This is useful for gracefully managing API errors. ```csharp try { var token = await client.GetAccessToken("ks:fiks"); } catch (UnexpectedResponseException ex) { Console.WriteLine($"Token request failed: {ex.Message}"); } ``` -------------------------------- ### Get On-Behalf-Of Access Token with IEnumerable Scopes Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClient.md Obtains an on-behalf-of access token. This feature has limited use cases and is planned for removal; delegation via ALTINN is preferred. Use this overload when scopes are provided as a collection. ```csharp public Task GetOnBehalfOfAccessToken( string consumerOrg, IEnumerable scopes) ``` ```csharp var token = await client.GetOnBehalfOfAccessToken( consumerOrg: "123456789", scopes: new[] { "ks:fiks" }); ``` -------------------------------- ### Token Cache GetToken Implementation Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenCache.md Illustrates the core logic for retrieving a token from the cache or fetching a new one if it's missing or expired. It uses a semaphore to ensure thread safety and prevent multiple concurrent fetches for the same token. ```csharp public async Task GetToken( TokenRequest tokenRequest, Func> tokenFactory) { // Acquire lock await _mutex.WaitAsync().ConfigureAwait(false); try { // Check if we have a valid cached token if (_cacheDictionary.ContainsKey(tokenRequest) && !_cacheDictionary[tokenRequest].IsExpiring()) { return _cacheDictionary[tokenRequest]; } // Cache miss or token expired - fetch new token var newToken = await tokenFactory().ConfigureAwait(false); // Update or add to cache if (_cacheDictionary.ContainsKey(tokenRequest)) { _cacheDictionary[tokenRequest] = newToken; } else { _cacheDictionary.Add(tokenRequest, newToken); } return newToken; } finally { // Release lock _mutex.Release(); } } ``` -------------------------------- ### Get Delegated Access Token with Scopes (IEnumerable) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClient.md Acquire a delegated access token for accessing APIs on behalf of another organization via ALTINN delegation. Requires the target organization's number and a collection of scopes. ```csharp var token = await client.GetDelegatedAccessToken( consumerOrg: "123456789", scopes: new[] { "ks:fiks" }); ``` -------------------------------- ### Load Certificate from System Store Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/configuration.md Load a certificate directly from the Windows certificate store. This is useful for managing certificates centrally and securely. You need to provide the certificate's thumbprint. ```csharp using System.Security.Cryptography.X509Certificates; var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly); var certs = store.Certificates.Find( X509FindType.FindByThumbprint, "your-certificate-thumbprint", validOnly: false); if (certs.Count > 0) { var certificate = certs[0]; var config = MaskinportenClientConfigurationFactory.CreateTestConfiguration( issuer: "my-issuer", certificate: certificate); } store.Close(); ``` -------------------------------- ### Load RSA Keys from PEM Files Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/configuration.md Configure the client using RSA private and public keys loaded from PEM-encoded files. This is a common method for asymmetric key cryptography. ```csharp using System.Security.Cryptography; var privateKeyPem = File.ReadAllText("path/to/private-key.pem"); var publicKeyPem = File.ReadAllText("path/to/public-key.pem"); var privateKey = RSA.Create(); privateKey.ImportFromPem(privateKeyPem); var publicKey = RSA.Create(); publicKey.ImportFromPem(publicKeyPem); var config = new MaskinportenClientConfiguration( audience: "https://test.maskinporten.no/", tokenEndpoint: "https://test.maskinporten.no/token", issuer: "my-issuer", numberOfSecondsLeftBeforeExpire: 10, privateKey: privateKey, publicKey: publicKey); ``` -------------------------------- ### MaskinportenClientConfiguration Constructor Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfiguration.md Initializes a new MaskinportenClientConfiguration with all the necessary parameters to connect to Maskinporten. This includes endpoint URLs, issuer details, authentication credentials (certificate or private/public keys), and token expiration settings. ```APIDOC ## MaskinportenClientConfiguration Constructor ### Description Initializes a new MaskinportenClientConfiguration. ### Method Signature ```csharp public MaskinportenClientConfiguration(string audience, string tokenEndpoint, string issuer, int numberOfSecondsLeftBeforeExpire, X509Certificate2 certificate = null, RSA privateKey = null, RSA publicKey = null, string keyIdentifier = null, string consumerOrg = null) ``` ### Parameters #### Constructor Parameters - **audience** (`string`) - Required - Maskinporten audience URL (typically `https://maskinporten.no/` or `https://test.maskinporten.no/`) - **tokenEndpoint** (`string`) - Required - Maskinporten token endpoint URL (e.g., `https://maskinporten.no/token`) - **issuer** (`string`) - Required - Issuer identifier (integration identifier from DigDir self-service portal) - **numberOfSecondsLeftBeforeExpire** (`int`) - Required - Seconds to subtract from token lifetime before treating it as expired. Triggers refresh when remaining lifetime falls below this threshold - **certificate** (`X509Certificate2`) - Optional - X.509 certificate containing both public and private keys. Either `certificate` OR `(privateKey, publicKey)` must be set - **privateKey** (`RSA`) - Optional - RSA private key for signing JWTs. Must be paired with `publicKey` if `certificate` is null - **publicKey** (`RSA`) - Optional - RSA public key. Must be paired with `privateKey` if `certificate` is null - **keyIdentifier** (`string`) - Optional - Optional key identifier to set in JWT `kid` header (used when multiple keys are configured) - **consumerOrg** (`string`) - Optional - Optional default 9-digit organization number. Used as fallback if not specified in individual token requests ### Validation - Throws `ArgumentException` if neither `certificate` nor (`privateKey` + `publicKey`) pair is provided - Throws `ArgumentException` if both `certificate` and (`privateKey` or `publicKey`) are provided simultaneously ### Example ```csharp using System.Security.Cryptography.X509Certificates; using Ks.Fiks.Maskinporten.Client; var certificate = new X509Certificate2("cert.pfx", "password"); var config = new MaskinportenClientConfiguration( audience: "https://test.maskinporten.no/", tokenEndpoint: "https://test.maskinporten.no/token", issuer: "my-integration-id", numberOfSecondsLeftBeforeExpire: 10, certificate: certificate, keyIdentifier: "key-1", consumerOrg: "987654321"); var client = new MaskinportenClient(config); ``` ``` -------------------------------- ### Get Delegated Access Token for Audience with Scopes (string) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Obtains an audience-restricted delegated token for a specified organization using a space-separated scope string. Provide the consumer organization's 9-digit number and the target audience. ```csharp Task GetDelegatedAccessTokenForAudience( string consumerOrg, string audience, string scopes) ``` -------------------------------- ### Initialize TokenRequest Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/TokenRequest.md Initializes a new empty TokenRequest. All properties are initially null and must be set individually or using the TokenRequestBuilder. ```csharp public TokenRequest() ``` -------------------------------- ### Get Delegated Access Token for Audience with Scopes (IEnumerable) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/IMaskinportenClient.md Obtains an audience-restricted delegated token for a specified organization. Requires the consumer organization's 9-digit number, the target audience identifier, and a collection of scope strings. ```csharp Task GetDelegatedAccessTokenForAudience( string consumerOrg, string audience, IEnumerable scopes) ``` -------------------------------- ### Manually Configure Production Environment Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/configuration.md Manually configure the Maskinporten client for the production environment. Specify audience, token endpoint, issuer ID, and certificate. ```csharp var config = new MaskinportenClientConfiguration( audience: "https://maskinporten.no/", tokenEndpoint: "https://maskinporten.no/token", issuer: "prod-issuer-id", numberOfSecondsLeftBeforeExpire: 10, certificate: productionCertificate); ``` -------------------------------- ### NumberOfSecondsLeftBeforeExpire Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/MaskinportenClientConfiguration.md The number of seconds subtracted from the token's reported `expires_in` value to determine when a cached token should be refreshed. For example, if a token is issued with `expires_in=3600` and this is set to `10`, the token is treated as expired after 3590 seconds. Read-only. Typical values: 10-30 seconds (default is 10). ```APIDOC ## NumberOfSecondsLeftBeforeExpire ### Description The number of seconds subtracted from the token's reported `expires_in` value to determine when a cached token should be refreshed. For example, if a token is issued with `expires_in=3600` and this is set to `10`, the token is treated as expired after 3590 seconds. ### Read-only True ### Typical Values 10-30 seconds (default is 10) ``` -------------------------------- ### Manually Configure Test Environment Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/configuration.md Manually configure the Maskinporten client for the test environment. Specify audience, token endpoint, issuer ID, and certificate. ```csharp var config = new MaskinportenClientConfiguration( audience: "https://test.maskinporten.no/", tokenEndpoint: "https://test.maskinporten.no/token", issuer: "test-issuer-id", numberOfSecondsLeftBeforeExpire: 10, certificate: testCertificate); ``` -------------------------------- ### Scoped Token Service Implementation in C# Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/README.md Provides a concrete implementation of an ITokenProvider interface for retrieving scoped access tokens. This pattern abstracts the token acquisition logic, making it easier to manage and inject dependencies. ```csharp public interface ITokenProvider { Task GetAccessToken(string scope); } public class MaskinportenTokenProvider : ITokenProvider { private readonly IMaskinportenClient _client; public MaskinportenTokenProvider(IMaskinportenClient client) { _client = client; } public async Task GetAccessToken(string scope) { var token = await _client.GetAccessToken(scope); return token.Token; } } ``` -------------------------------- ### UnexpectedResponseException(string) Source: https://github.com/ks-no/fiks-maskinporten-client-dotnet/blob/main/_autodocs/api-reference/UnexpectedResponseException.md Initializes a new UnexpectedResponseException with a detailed message. ```APIDOC ## UnexpectedResponseException(string message) ### Description Initializes a new `UnexpectedResponseException` with a detailed message. ### Parameters #### Path Parameters - **message** (string) - Required - Error message describing the unexpected response ### Example ```csharp throw new UnexpectedResponseException("Got unexpected HTTP Status code 401 from https://maskinporten.no/token. " + "Content: Invalid assertion"); ``` ```