Examples for setting up authorization /businessnxtapi/authentication/web/examples section Here you can find some examples for how to set up authorization. 2024-09-24T15:57:29+02:00 # Examples for setting up authorization Here you can find some examples for how to set up authorization. Click the links below to look at examples for how to set up authorization for either .NET, Postman, or Insomnia. .NET Code Sample /businessnxtapi/authentication/web/examples/code page .NET sample app for integrating with Business NXT using OAuth flow. Clone or create ASP.NET app, setup configs, run to authenticate. 2024-09-24T15:57:29+02:00 # .NET Code Sample .NET sample app for integrating with Business NXT using OAuth flow. Clone or create ASP.NET app, setup configs, run to authenticate. If you're using .NET (3.1/5/6) to build your application that integrates with Business NXT, you can set it up as described below to perform the oauth flow. > [!NOTE] > > The code for the application described here is available on GitHub at [GraphQLSamples/MvcCode](https://github.com/Visma-Business/GraphQLSamples/tree/main/MvcCode). > > This application is a modified version of the [MvcCode sample](https://github.com/IdentityServer/IdentityServer4/tree/main/samples/Clients/src/MvcCode) from the [IdentityServer](https://github.com/IdentityServer) project. ## Getting started You can either clone the MvcCode sample repository or create an Asp.Net application from scratch. The sample application described here has the following structure: ![Project structure](../codesample1.png) ## Application setup The `Program.cs` source file has the following content: ``` using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; namespace MvcCode { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); } } ``` The `Setup.cs` source file contains the following: ``` using IdentityModel; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Net.Http; using IdentityModel.Client; using Microsoft.IdentityModel.Logging; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; namespace MvcCode { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { JwtSecurityTokenHandler.DefaultMapInboundClaims = false; services.AddControllersWithViews(); services.AddHttpClient(); services.AddOptions(); services.Configure(Configuration); services.AddSingleton(r => { var factory = r.GetRequiredService(); return new DiscoveryCache(Configuration.GetValue("Authority"), () => factory.CreateClient()); }); services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = "oidc"; }) .AddCookie(options => { options.Cookie.Name = "mvccode"; }) .AddOpenIdConnect("oidc", options => { options.Events.OnTokenResponseReceived = (tokenResponse) => { var accessToken = tokenResponse.TokenEndpointResponse.AccessToken; return Task.CompletedTask; }; options.Events.OnRemoteFailure = (err) => { return Task.CompletedTask; }; options.Events.OnMessageReceived = (msg) => { return Task.CompletedTask; }; options.Authority = Configuration.GetValue("Authority"); options.RequireHttpsMetadata = false; options.ClientId = Configuration.GetValue("ClientId"); options.ClientSecret = Configuration.GetValue("ClientSecret"); options.ResponseType = "code id_token"; options.UsePkce = true; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("email"); options.Scope.Add("business-graphql-api:access-group-based"); options.Scope.Add("offline_access"); options.GetClaimsFromUserInfoEndpoint = true; options.SaveTokens = true; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = JwtClaimTypes.Name, RoleClaimType = JwtClaimTypes.Role, }; }); } public void Configure(IApplicationBuilder app) { IdentityModelEventSource.ShowPII = true; app.UseDeveloperExceptionPage(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute() .RequireAuthorization(); }); } } } ``` From this snippet, you should notice the following: - Authority, client ID, and client secret are read from the application settings. - The response type is `code id_token`. - The requested scopes are `openid`, `profile`, `email`, `business-graphql-api:access-group-based`, and `offline_access`. The latter is only needed when offline access is required. ## Application Settings The JSON file with the application settings (`appsettings.json`) looks as follows: ``` { "ClientId": "...", "ClientSecret": "...", "Authority": "https://connect.visma.com", "SampleApi": "https://localhost:5005/" } ``` The client ID is the one you specified when you registered your application with the Visma Developer Portal. The client secret is a value generated in the **Credentials** tab of the application propertys in the Visma Developer Portal. > [!NOTE] > > Make sure you do not upload the content of this file to a public repository such as on GitHub. The `AppSettings.cs` file contains the following class definition used to help with accessing the settings: ``` namespace MvcCode { public class AppSettings { public string ClientId { get; set; } public string ClientSecret { get; set; } public string Authority { get; set; } public string SampleApi { get; set; } } } ``` ## Controllers The `HomeController` class is implemented as follows: ``` using System; using System.Globalization; using System.Net.Http; using System.Threading.Tasks; using IdentityModel.Client; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; namespace MvcCode.Controllers { public class HomeController : Controller { private readonly IHttpClientFactory _httpClientFactory; private readonly IDiscoveryCache _discoveryCache; private readonly AppSettings _authSettings; public HomeController(IHttpClientFactory httpClientFactory, IDiscoveryCache discoveryCache, IOptions authSettings) { _httpClientFactory = httpClientFactory; _discoveryCache = discoveryCache; _authSettings = authSettings.Value; } [AllowAnonymous] public IActionResult Index() => View(); public IActionResult Secure() => View(); public IActionResult Logout() => SignOut("oidc"); public async Task CallApi() { var token = await HttpContext.GetTokenAsync("access_token"); var client = _httpClientFactory.CreateClient(); client.SetBearerToken(token); var response = await client.GetStringAsync(_authSettings.SampleApi + "identity"); ViewBag.Json = JArray.Parse(response).ToString(); return View(); } public async Task RenewTokens() { var disco = await _discoveryCache.GetAsync(); if (disco.IsError) throw new Exception(disco.Error); var rt = await HttpContext.GetTokenAsync("refresh_token"); var tokenClient = _httpClientFactory.CreateClient(); var tokenResult = await tokenClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = disco.TokenEndpoint, ClientId = _authSettings.ClientId, ClientSecret = _authSettings.ClientSecret, RefreshToken = rt }); if (!tokenResult.IsError) { var oldIdToken = await HttpContext.GetTokenAsync("id_token"); var newAccessToken = tokenResult.AccessToken; var newRefreshToken = tokenResult.RefreshToken; var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn); var info = await HttpContext.AuthenticateAsync("Cookies"); info.Properties.UpdateTokenValue("refresh_token", newRefreshToken); info.Properties.UpdateTokenValue("access_token", newAccessToken); info.Properties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture)); await HttpContext.SignInAsync("Cookies", info.Principal, info.Properties); return Redirect("~/Home/Secure"); } ViewData["Error"] = tokenResult.Error; return View("Error"); } } } ``` In this snippet: - `CallApi()` is a function that makes an HTTP request to (or whatever base URL is specified in the `SampleApi` property in the application settings). - `RenewTokens()` is a function that runs the oauth flow to refesh the access token. ## Views The view files are as follows: - `Index.cshtml` ``` @{ ViewData["Title"] = "Home Page"; } ``` - `CallApi.cshtml` ```

API Response

@ViewBag.Json
``` - `Secure.cshtml` ```

API Response

@ViewBag.Json
``` ## Running the Application When you run the application (for instance on port 44303 at or ) you get the following welcome page: ![Home Page](../codesample2.png) When you click on **Secure** you are redirected to Visma Connect for authentication: ![Authentication](../codesample3.png) After completing the authentication, the **Secure** page lists your user identity claims: ![Claims](../codesample4.png) You can also find, on the same page, the authentication properties, such as the ID token, the access token, and the refresh token: ![Properties](../codesample5.png)
Postman /businessnxtapi/authentication/web/examples/postman page Configure Postman authorization using Bearer tokens per request or collection. Learn more in the official Postman documentation. 2024-09-24T15:57:29+02:00 # Postman Configure Postman authorization using Bearer tokens per request or collection. Learn more in the official Postman documentation. In Postman, you can set the authorization method and details either per request or collection. You must use the **Bearer token** authorization type and specify an access token. You can fetch an access token in different ways. A possible way is using the .NET sample application described [here](code.md). ![Configure Authorization - Postman](../postman4.png) > [!TIP] > > You can learn more about about authentication in Postman from its official documentation. See [Authorizing requests](https://learning.postman.com/docs/sending-requests/authorization/). Insomnia /businessnxtapi/authentication/web/examples/insomnia page Set up Insomnia with Bearer Token authorization, fetch access tokens via .NET application, and learn more about authentication techniques. 2024-09-24T15:57:29+02:00 # Insomnia Set up Insomnia with Bearer Token authorization, fetch access tokens via .NET application, and learn more about authentication techniques. In Insomnia, you can set the authorization method and details per request. You must use the **Bearer Token** authorization type and specify an access token. You can fetch an access token in different ways. A possible way is using the .NET sample application described [here](code.md). ![Configure Authorization - Insomnia](../insomnia7.png) > [!TIP] > > You can read more about authentication in Insomnia [here](https://docs.insomnia.rest/insomnia/authentication).