<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kayes Islam</title>
    <description>The latest articles on DEV Community by Kayes Islam (@kayesislam).</description>
    <link>https://dev.to/kayesislam</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F641003%2Fc86edfd4-7723-404d-9e61-1081535fe643.jpeg</url>
      <title>DEV Community: Kayes Islam</title>
      <link>https://dev.to/kayesislam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kayesislam"/>
    <language>en</language>
    <item>
      <title>Integrating OpenID Connect to your application stack (Asp.Net Core, Angular)</title>
      <dc:creator>Kayes Islam</dc:creator>
      <pubDate>Tue, 29 Jun 2021 11:17:13 +0000</pubDate>
      <link>https://dev.to/kayesislam/integrating-openid-connect-to-your-application-stack-25ch</link>
      <guid>https://dev.to/kayesislam/integrating-openid-connect-to-your-application-stack-25ch</guid>
      <description>&lt;p&gt;Today I wanted to write about how you can integrate OpenID Connect JWT token based authentication in your application stack, Asp.net Core Web API for the back-end and Angular for the front-end. Even if you don't use these technologies, I hope the article will give you some idea of the steps involved.&lt;/p&gt;

&lt;p&gt;Most code I have included here comes from the github repo that I have reference at the end of the article.&lt;/p&gt;

&lt;h2&gt;
  
  
  JWT
&lt;/h2&gt;

&lt;p&gt;JWT (JSON Web Token) is a critical piece in OpenID Connect. The client application (such as an Angular SPA), obtains a JWT access token from the authentication server using one of the pre-defined OAuth flows. It then passes the token with requests to the Resource Server (such as Asp.net Core Web API). The resource server evaluates the token and accepts/rejects the request based on it. Given the importance of JWT, Let's start with a quick introduction of JWT tokens. The &lt;a href="https://jwt.io/introduction"&gt;JWT Introduction&lt;/a&gt; explains it very well, but here are some of the points as summary. &lt;/p&gt;

&lt;p&gt;JWT is a self contained token, meaning it carries it's own signature to verify it's validity. This means that to validate a JWT token, the resource server does not need to query the Auth server asking if the token is valid. It just needs to validate the signature that is carried within the token. Here's a sample JWT token:&lt;/p&gt;

&lt;p&gt;eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0ZWFSLVJTS2QwdHhXejZSWnR2TVROazByVkVncFR2Qnd0QlhLbGlKMVF3In0&lt;code&gt;.&lt;/code&gt;eyJleHAiOjE2MjQzNzYwODIsImlhdCI6MTYyNDM3NTQ4MiwiYXV0aF90aW1lIjoxNjI0Mzc0Mjc2LCJqdGkiOiJmZjQ2YzJmNy1hNjkxLTQzNTQtOTUzNC1lODY4YTA4YzkzNGQiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvQXV0aERlbW9SZWFsbSIsImF1ZCI6ImF1dGgtZGVtby13ZWItYXBpIiwic3ViIjoiYjEyMWEzNDMtYTk1OC00MTJhLTg3YzAtNzFhNGE3NmRmNTBhIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiYXV0aC1kZW1vLXNwYSIsIm5vbmNlIjoiNjgzNTY3YWVmZjk5NDcyYmRlNzJiZDgyMDk4MGE0NTY2N3RSQWRrMTgiLCJzZXNzaW9uX3N0YXRlIjoiNTMyZDExZWEtZTU1My00Mjc2LWFiMDItYThkNjRjOWU2OWE5IiwiYWNyIjoiMCIsInNjb3BlIjoib3BlbmlkIGVtYWlsIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IkRlbW8gVXNlciIsInByZWZlcnJlZF91c2VybmFtZSI6ImRlbW8udXNlciIsImdpdmVuX25hbWUiOiJEZW1vIiwiZmFtaWx5X25hbWUiOiJVc2VyIiwiZW1haWwiOiJkZW1vLnVzZXJAZW1haWwuY29tIn0&lt;code&gt;.&lt;/code&gt;U3qv-ujxq5axhLYeEON4ofDmd2CH_RLDhY3KBK8gNJkAYIx3dhCMI-4mNjIPxkpXjXdF1Ci7fX2zM9AN8_d2nVhYQB7dusdvjxRAfzu_IzAPhl4hZXNxEIJYd2f6KBVU_gnSKgJyEi5LJ89blYIllbyN5KfPke_DIZgL3CfhUiAGqE5eW7UY1weOTjcGsV29u5vv_FcONmk2z_uTDH9qN7g-xTVkEv3tr-u7osK4T8fwoxWA62TlTyxefr_ZsDDyy3nGCL_YhDTdzqASs5_Xc60vaP0x3BmdAHXM4-p0xgei6qOv9g4FYy_3u1DUAnoXY6g-Nls-MVs1K18f8H2ZfA&lt;/p&gt;

&lt;p&gt;JWT tokens are separated into three parts by dots (.):&lt;/p&gt;

&lt;h4&gt;
  
  
  JWT Header
&lt;/h4&gt;

&lt;p&gt;The first part is the JWT header. This is just Base64Url encoded, &lt;strong&gt;not encrypted&lt;/strong&gt;, which means anyone can decode it, for example using an online tool such as &lt;a href="https://www.base64decode.org/"&gt;this one&lt;/a&gt;. Therefore, it does not contain any secret, which is important to note. If you put the first part of the token (separated by .) in the tool and decode you get the following JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "4eaR-RSKd0txWz6RZtvMTNk0rVEgpTvBwtBXKliJ1Qw"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other than the obvious typ (type) JWT, the header tells us that the token is signed using RS256 algorithm and a kid (Key ID) of the token. Both of these come into play when we need to validate the token with the signature. More on this below.&lt;/p&gt;

&lt;h4&gt;
  
  
  JWT Payload
&lt;/h4&gt;

&lt;p&gt;The second part of the JWT token is the payload which is also just Base64Url encoded, which means anyone can decode it. (&lt;a href="https://www.base64decode.org/"&gt;Online decoding tool&lt;/a&gt;). If you copy the 2nd part of the token above decode it you get the following JSON payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "exp": 1624376082,
  "iat": 1624375482,
  "auth_time": 1624374276,
  "jti": "ff46c2f7-a691-4354-9534-e868a08c934d",
  "iss": "http://localhost:8080/auth/realms/AuthDemoRealm",
  "aud": "auth-demo-web-api",
  "sub": "b121a343-a958-412a-87c0-71a4a76df50a",
  "typ": "Bearer",
  "azp": "auth-demo-spa",
  "nonce": "683567aeff99472bde72bd820980a45667tRAdk18",
  "session_state": "532d11ea-e553-4276-ab02-a8d64c9e69a9",
  "acr": "0",
  "scope": "openid email profile",
  "email_verified": true,
  "name": "Demo User",
  "preferred_username": "demo.user",
  "given_name": "Demo",
  "family_name": "User",
  "email": "demo.user@email.com"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these properties of the payload is called claims. There are some standard claims such as iss (issuer), aud (audience) etc. Some of these are mandatory claims such as the exp (expiry) which must be present. I usually go to the &lt;a href="https://datatracker.ietf.org/doc/html/rfc7519"&gt;JWT Spec&lt;/a&gt; here to look up the standard claims and what they mean, the document is easy to read and understand.&lt;/p&gt;

&lt;p&gt;Other than the standard claims the payload may have custom claims. In the above example email_verified and preferred_username are such custom claims handing out by Keycloak with the out of the box configuration. &lt;/p&gt;

&lt;p&gt;Important to note here again, there are no secrets in the payload. But for an access token, it should contain enough information for the resource owner (Web API backend in our case) to evaluate if access to data should be granted.  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;scope&lt;/code&gt; claim is a special one that needs a bit of attention. A scope is a grouping claims and it's requested by the client app. In the example above &lt;code&gt;given_name&lt;/code&gt; and &lt;code&gt;family_name&lt;/code&gt; claims are present because the client app requested the &lt;code&gt;profile&lt;/code&gt; scope. Just because the client requested a scope doesn't mean the auth server will provide the claims for that scope in the payload, it depends on many factors. For example the scope maybe configured on the authorisation server in a way that it requires to present consent screen to the user and will only be provided if user has given consent. The &lt;code&gt;scope&lt;/code&gt; claim in the JWT payload basically tells us which scopes have been provided in the payload, in this case &lt;code&gt;openid&lt;/code&gt; (which is the standard scope for OpenID Connect, must be preset), &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;profile&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;It's a very common practice to have custom resource oriented scopes. Let's elaborate a little further with an example. Let's say you are working with an Auth server that logs in tradies to use your application. The auth server provides a &lt;code&gt;trade_license&lt;/code&gt; scope, which adds claims &lt;code&gt;trade_license_number&lt;/code&gt; and &lt;code&gt;trade_license_expiry&lt;/code&gt; to the token. When the clien app requests for the &lt;code&gt;trade_license&lt;/code&gt; scope, user is asked during login: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This application wants to access your trade license information. Do you accept? [yes | no].&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If user selects no, the &lt;code&gt;trade_license&lt;/code&gt; scope is not provided as part of the &lt;code&gt;scope&lt;/code&gt; claim, &lt;code&gt;trade_license_number&lt;/code&gt; and &lt;code&gt;trade_license_expiry&lt;/code&gt; claims are not provided with the payload. If user answers yes these claims are provided. &lt;/p&gt;

&lt;p&gt;In asp.net core you can enable policy based authentication allowing you to check wether a scope exists or if a claim has an expected value. More on that later.&lt;/p&gt;

&lt;h4&gt;
  
  
  JWT Signature
&lt;/h4&gt;

&lt;p&gt;The third part of the JWT token is the signature which ensures that the token has originated from the auth server and it has not been tinkered with. The signature is constructed with the first two parts and a secret. As a result the generated signature is only valid for the header and payload data of the token, which ensures that no one can change the content of the header and payload. The use of secret to create the token ensures that only the server can generate a signature. There are two types of algorithms for creating the token signature, symetric and asymetric.&lt;/p&gt;

&lt;h5&gt;
  
  
  Symetric Algorithms
&lt;/h5&gt;

&lt;p&gt;The symetric algorithoms use a secret, along with the first two parts of the token to generate the signature. To validate the token, the receiver of the token would then need to use the same secret. The fact that the secret has to be known by the auth server as well as the resource server poses a few limitations such as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Automatically changing the secret is not easy. If the secret is exposed and you need to change it, you'd have to do that on all the resource servers. &lt;/li&gt;
&lt;li&gt;You cant use the secret on "untrusted" applications where the source code is open or can easily be reversed-engineered, such as a browser app or a mobile app.&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  Asymetric Algorithms
&lt;/h5&gt;

&lt;p&gt;Because of the limitations above, usually asymatric algorithoms are used to create JWT signature. Asymetric algorithms use a private key to sign the token, and exposes a public key that can be used to verify the token. So the private key used to create the token is never exposed. The public key is available to retrieve from an &lt;code&gt;.well-known&lt;/code&gt; endpoint called &lt;code&gt;jwks_uri&lt;/code&gt;. Since the resource server is not dependent on a shared key, this enables a key-rotation mechanism, ensuring that the private-public keys are rotated regularly to ensure extra security against key leaks. &lt;/p&gt;

&lt;h2&gt;
  
  
  Resource Server - Validating the Token
&lt;/h2&gt;

&lt;p&gt;Now let's see what we need to do to validate that token we've been provided on the resource server. You'll need to do these steps below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check to see if the token has been expired.&lt;/li&gt;
&lt;li&gt;Check the &lt;code&gt;iss&lt;/code&gt; (issuer) claim to ensure that the token has been issued by the right auth server.&lt;/li&gt;
&lt;li&gt;(Optional) Check the &lt;code&gt;aud&lt;/code&gt; (audience) claim to ensure that the resource server is one of the audiences.&lt;/li&gt;
&lt;li&gt;Check to see if the token has a valid signature. 

&lt;ol&gt;
&lt;li&gt;Download the public key for from &lt;code&gt;jwks_uri&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Validate the token with the public key. &lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;(Optional) Check required scopes are present.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When using Asp.net core (3.1/5) we're just going to use the provided middleware that does it all. This is how you can configure it as a minimum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services
    .AddAuthentication()
    .AddJwtBearer(x =&amp;gt;
    {
        x.MetadataAddress = "http://keycloak:8080/auth/realms/AuthDemoRealm/.well-known/openid-configuration";
        x.TokenValidationParameters = new TokenValidationParameters
        {
            ValidAudience = "auth-demo-web-api"                    
        };
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! &lt;code&gt;MetadataAddress&lt;/code&gt; is set to the &lt;code&gt;.well-known&lt;/code&gt; endpoint. The middleware can retrieve the following required properties from the &lt;code&gt;.well-known&lt;/code&gt; edn-point:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The issuer&lt;/li&gt;
&lt;li&gt;The  &lt;code&gt;jwks_uri&lt;/code&gt; from where it needs retrieve the public key to validate the token signature. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that you have a valid token configuration you can configure claims based authorisation for default authorisation policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.AddAuthorization(o =&amp;gt;
{
    o.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .RequireClaim("email_verified", "true")
        .Build();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we are saying there in effect is that the default &lt;code&gt;Authorize&lt;/code&gt; attribute on a controller or action will return unauthorised if the token doesn't have the claim &lt;code&gt;email_verified&lt;/code&gt; with value &lt;code&gt;true&lt;/code&gt;. Here's an example of a controller that's using the default plicy to authorise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ApiController]
[Route("[controller]")]
[Authorize]
public class EamilController : ControllerBase
{
    // ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could have different named policies as well along with the default policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.AddAuthorization(o =&amp;gt;
{
    o.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .RequireClaim("email_verified", "true")
        .Build();

    var tradieAuthorizerPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .RequireClaim("trade_license_number")
        .Build();
    o.AddPolicy("TradieOnly", tradieAuthorizerPolicy);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could then apply the named policy by setting &lt;code&gt;Policy&lt;/code&gt; value of the &lt;code&gt;Authorization&lt;/code&gt; attribute. In the example below anyone can post a job, but only tradies, with a trade_license_number as per the policy configuration above, are authorised to apply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ApiController]
[Route("[controller]")]
[Authorize()]
public class JobsController : ControllerBase
{
    [Authorize( Policy = "TradieOnly")]
    public async Task Apply(JobApplication jobApplication)
    {
        // ...
    }

    public async Task PostJob(Job job)
    {
        // ...
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checkout the &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction?view=aspnetcore-3.1"&gt;Authorisation section&lt;/a&gt; for Asp.net core for more information on claims based and policy based authorisation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client App - Obtaining the Token
&lt;/h2&gt;

&lt;p&gt;There are a number of flows defined in OAuth2 to obtain the access token. For untrusted clients it's &lt;strong&gt;Authorisation Code Flow with Proof Key for Code Exchange (PKCE)&lt;/strong&gt;. In a nutshell these are the steps from when user clicks login button to obtaining the access token:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client app creates a random &lt;code&gt;Code Verifier&lt;/code&gt; and a &lt;code&gt;Code Challenge&lt;/code&gt; hash from it.&lt;/li&gt;
&lt;li&gt;Redirects to the auth server's authorisation endpoint. This endpoint is usually published in &lt;code&gt;.well-known&lt;/code&gt; JSON for the auth server. The client app passes the following parameters as a minimum with the redirect:

&lt;ul&gt;
&lt;li&gt;Redirect URL: The URL where the auth server will redirect back to once the authorisation is complete (successful or failed)&lt;/li&gt;
&lt;li&gt;Code Challenge: This is part of the PKCE flow. Later we pass in the code verifier for the challenge when we request access code. see below.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The server performs N number of steps as required to authenticate the user. These steps usually include:

&lt;ul&gt;
&lt;li&gt;Username+password prompt&lt;/li&gt;
&lt;li&gt;Password change prompt when password has expired&lt;/li&gt;
&lt;li&gt;Accept new terms and conditions prompt&lt;/li&gt;
&lt;li&gt;Setting up some another MFA, etc&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;At the end of it all, once the user is authorized, the server redirects back to the &lt;code&gt;Redirect URL&lt;/code&gt; we passed in Step 2. The server provides an &lt;code&gt;Authorisation Code&lt;/code&gt; with the redirect, which is a one time code that can be used by the client app to obtain the &lt;code&gt;Access Token&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The client app requests for the access token at the &lt;code&gt;/token&lt;/code&gt; endpoint using the provided &lt;code&gt;Authorization Code&lt;/code&gt; and the &lt;code&gt;Code Verifier&lt;/code&gt; created in step 1. The endpoint to obtain the token is usually published in the &lt;code&gt;.well-known&lt;/code&gt; JSON.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If all is successful, the client app will have an access token that it can be pass in with the &lt;code&gt;authorization&lt;/code&gt; header for restricted resources.&lt;/p&gt;

&lt;p&gt;Even tough all the steps above maybe easy to write by yourself, I recommend against it. My suggestion is that you use a client library that does these steps for you. I always prefer using code written by the experts, well tested and possibly improved over time based on other users experiences, specially when it comes to security. On the same note avoid libraries that are not quite OpenID Connect compatible, not easy to configure or requires you to do some steps manually. For example the &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-overview"&gt;MSAL&lt;/a&gt; library, avoid if you are implementing an OIDC client.&lt;/p&gt;

&lt;p&gt;If you are using Angular, I highly recommend using &lt;a href="https://www.npmjs.com/package/angular-auth-oidc-client"&gt;angular-auth-oidc-client&lt;/a&gt; npm package. The library is OpenID Certified. Below is my client configuration and &lt;code&gt;angular-auth-oidc-client&lt;/code&gt; does all of the above steps to ensure the the access token is available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oidcConfigService.withConfig({
  authWellknownEndpoint: 'http://localhost:8080/auth/realms/AuthDemoRealm/.well-known/openid-configuration',
  redirectUrl: `${window.location.origin}/home`,
  clientId: 'auth-demo-spa',
  scope: 'openid profile email',
  responseType: 'code',
  triggerAuthorizationResultEvent: true,
  postLogoutRedirectUri: `${window.location.origin}/home`,
  startCheckSession: false,
  postLoginRoute: '',
  unauthorizedRoute: '/unauthorized',
  logLevel: LogLevel.Debug
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first 5 lines in the configuration are really the most important ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authWellKnownEndpoint: We're setting the &lt;code&gt;.well-known&lt;/code&gt; URI here. The client library should know the following important endpoints from here:

&lt;ul&gt;
&lt;li&gt;authorisation URL where it should redirect to to start the auth process&lt;/li&gt;
&lt;li&gt;Token endpoint where it can request the access token using the authorisation code (at the end of a successful flow).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;redirectUrl: The URL where the auth server will redirect back to once authentication is successful. Usually you need to configure this on the Auth server as well, otherwise you'll get an error. 
clientId: You must configure a client on the auth server and pass in the configured client's client-id here. &lt;/li&gt;
&lt;li&gt;scope: Scopes requested. You must have &lt;code&gt;openid&lt;/code&gt; for OpenID Connect claims. &lt;/li&gt;
&lt;li&gt;responseType: Should be set to &lt;code&gt;code&lt;/code&gt; for Authorisation Code Flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below are my &lt;code&gt;login()&lt;/code&gt; and &lt;code&gt;logout()&lt;/code&gt; methods hooked to the login/logout buttons.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;login() {
  this.oidcSecurityService.authorize();
}

logout() {
  this.oidcSecurityService.logoff();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The library ensures that the access code is refreshed using refresh token automatically. Below is the code that gets the access token that is already available if the user has logged in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let apiUrl = `${environment.baseApiUrl}/weatherforecast`;
let accessToken = this.oidcSecurityService.getToken();
let headers = {};
if(accessToken)
  headers['authorization'] = `Bearer ${accessToken}`;
this.data = await this.httpClient
  .get(apiUrl, {
    headers: headers
  })
  .pipe(take(1))
  .toPromise();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Authentication Responsibility Separation
&lt;/h2&gt;

&lt;p&gt;Developing your application layers to work with OpenID Connect as in the example above means that you are separating the authentication responsibility from your application code. For example, if you have configured Azure B2C for your auth provider, you can just change the configuration on your asp.net core app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services
    .AddAuthentication()
    .AddJwtBearer(x =&amp;gt;
    {
        x.MetadataAddress = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
        x.TokenValidationParameters = new TokenValidationParameters
        {
            ValidAudience = "auth-demo-web-api"                    
        };
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and your Angular app as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oidcConfigService.withConfig({
  authWellknownEndpoint: 'https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration',
  redirectUrl: `${window.location.origin}/home`, // need to configure
  clientId: 'auth-demo-spa', // need to configure
  scope: 'openid profile email',
  responseType: 'code',
  triggerAuthorizationResultEvent: true,
  postLogoutRedirectUri: `${window.location.origin}/home`,
  startCheckSession: false,
  postLoginRoute: '',
  unauthorizedRoute: '/unauthorized',
  logLevel: LogLevel.Debug
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and it now works with Microsoft Login. If want to use AWS Cognito as your auth provider, set-up a user-pool, find out how to get the &lt;code&gt;.well-known&lt;/code&gt; endpoint, configure the server and the client and you're good to go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There are a number of good libraries out there to help you integrate the authentication mechanism for whatever framework you are using and you should resort to these libraries to do the heavy lifting for you. Because the last thing you want is to leave a security whole trying to write it all by yourself. Oh and stay away from MSAL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Code
&lt;/h2&gt;

&lt;p&gt;Here's the github repo from one of my earlier posts that has Keycloak as auth server, Asp.net Core Web API as resource server and Angular client app. This should give you a starting point if you would like to play with even some other auth server configurations:&lt;br&gt;
&lt;a href="https://github.com/Kayes-Islam/keycloak-demo"&gt;Kayes-Islam / keycloak-demo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>dotnet</category>
      <category>aspnetcore</category>
      <category>jwt</category>
    </item>
    <item>
      <title>Keycloak - highly customisable auth server</title>
      <dc:creator>Kayes Islam</dc:creator>
      <pubDate>Tue, 15 Jun 2021 11:01:06 +0000</pubDate>
      <link>https://dev.to/kayesislam/keycloak-as-oidc-provider-42ip</link>
      <guid>https://dev.to/kayesislam/keycloak-as-oidc-provider-42ip</guid>
      <description>&lt;p&gt;I have recently been working with Keycloak as an identity solution for our project. Keycloak is an open source auth server written in Java distributed with Apache 2 license. In the past I have worked with Azure B2C, AWS Cognito and Identity Server 4. Compared with those, even though some are in different categories, I have been quite impressed with Keycloak. It has a good set of documentation and customisation options available making it suitable for any greenfield project as well as an existing application where you feel the need to upgrade your old authentication mechanism to Open ID Connect (OIDC).&lt;/p&gt;

&lt;h2&gt;
  
  
  DEMO
&lt;/h2&gt;

&lt;p&gt;I've put together a demo that you can run with docker compose so that you can try out the features. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the source from here: &lt;a href="https://github.com/Kayes-Islam/keycloak-demo" rel="noopener noreferrer"&gt;Kayes-Islam / keycloak-demo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;docker compose up --build&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This exposes three services, Keycloak on port 8080, and Angular SPA on port 4200 and an asp.net core web-api on 5000. Note that the Keycloak service takes half a minute or so to get up an running so wait for it to start up.&lt;/p&gt;

&lt;p&gt;Open up the client app at &lt;a href="http://localhost:4200" rel="noopener noreferrer"&gt;http://localhost:4200&lt;/a&gt;. Click the Call API button without logging in and you'll see the web-api returning 401 un-authorized error. But if you login using the demo account below and then click "Call API" you'll see successful response with JSON data.&lt;br&gt;
Demo User:&lt;br&gt;
U: demo.user&lt;br&gt;
P: P@ssw0rd&lt;/p&gt;

&lt;p&gt;NOTE: If you are having an issue logging in check the console logs from the SPA. It should have an error entry that says "iat time too far in the past". "iat" is issued at time. This happens when your container's time is not in sync with your host machines time. This is an issue on WSL/WSL2 on windows, specially if you have a laptop that is set to sleep after inactivity, because when windows wakes up, it doesn't re-sync the time  on the WSL.&lt;br&gt;
FIX: Open WSL console on windows then run &lt;code&gt;hwclock -s&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;Now that you've got a demo up and running, let's talk about a few reasons I would recommend anyone to consider Keycloak as an auth solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy to use admin portal
&lt;/h3&gt;

&lt;p&gt;Keycloak has a great admin portal that is easy to configure out of the box. If you are running the demo, open up &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; and login as admin user to have a look around:&lt;br&gt;
U: admin&lt;br&gt;
P: admin &lt;/p&gt;

&lt;p&gt;Here are a few screenshots of how I have configured the client-app:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxz00fqrcmgskshwj74kx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxz00fqrcmgskshwj74kx.png" alt="Realm Settings - General"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpp2emv4m3xykit44mbt3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpp2emv4m3xykit44mbt3.png" alt="Realm Settings - Login Options"&gt;&lt;/a&gt; &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frodiiwkbbi0grp2b7fm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frodiiwkbbi0grp2b7fm5.png" alt="Client Configurations - Settings"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Customizable Themes
&lt;/h3&gt;

&lt;p&gt;From sing-up page to admin portal, you can customize pretty much any part of the UI using custom themes. Themes are developed using &lt;a href="https://freemarker.apache.org/" rel="noopener noreferrer"&gt;Freemarker Templates&lt;/a&gt; and it's all documented &lt;a href="https://freemarker.apache.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extensible with &lt;a href="https://www.keycloak.org/docs/latest/server_development/#_providers" rel="noopener noreferrer"&gt;Service Provider Interfaces (SPIs)&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Everything in Keycloak has been implemented using injectable providers. You can register custom implementations of the provider interfaces in Java, drop the jar file in the deployments directory and it's available to be configured. There are many extensible SPIs available in Keycloak, but below are two of the most important one's in my opinion:&lt;/p&gt;

&lt;h4&gt;
  
  
  Storage SPI
&lt;/h4&gt;

&lt;p&gt;Do you have an existing user database that does not currently have OpenID Connect capabilities? Keycloaks User Storage SPI allows you to extend the storage and retrieval of user data. You basically extend the UserStorageProvider class and implement a bunch of interfaces in Java with methods such as getUserById(), isValid() etc. The benefits you get is an OIDC solution on top of your existing infrastructure, with all the capabilities that come with it such as OAuth2, discovery, user registration, client registration, account management, admin portal etc just to name a few. &lt;a href="https://www.keycloak.org/docs/latest/server_development/#_user-storage-spi" rel="noopener noreferrer"&gt;Here&lt;/a&gt; are the docs. I have recently worked on such a project to create a Storage SPI for existing user database and it works very well. &lt;/p&gt;

&lt;h4&gt;
  
  
  Authentication SPI
&lt;/h4&gt;

&lt;p&gt;Using the authentication SPI you can create a custom challenge, add an extra authentication step, or replace the entire flow if that's what your requirement is. Maybe you are creating an auth solution is for the tradies. So when users sign up, you want them to enter a their trade license number. Maybe you want to validate the trade license every-time they log in to ensure it's not expired. You can implement all that using a custom Authentication SPI and configure it as part of the flows for your realm. &lt;a href="https://www.keycloak.org/docs/latest/server_development/#_auth_spi" rel="noopener noreferrer"&gt;See here&lt;/a&gt; for more.&lt;/p&gt;

&lt;h3&gt;
  
  
  LDAP and Kerberos integration
&lt;/h3&gt;

&lt;p&gt;Although I haven't tried these features yet, they look really good on the documentation. These stood out to me at first glance because I have worked with some applications in the past that rely on Active Directory for authentication. Keycloak comes with an LDAP provider which is just an implementation of User Storage SPI. Therefore when configured can it retrieve user information or validate user credentials with Active Directory. &lt;a href="https://www.keycloak.org/docs/7.0/server_admin/#_ldap" rel="noopener noreferrer"&gt;See here&lt;/a&gt; for more info.&lt;/p&gt;

&lt;p&gt;Keycloak also allows you to configure Kerberos authentication. Note that both LDAP and Kerberos integration are separate pieces, you can configure only one or both. This let's Keycloak deal with LDAP/Kerberos hand-shake providing an OIDC solution on top. I think this is a great separation to have since it frees your application, the resource server (back-end) and the client app (front-end), to be developed against the OIDC standard. That way you can just plug in the auth server. You may have one deployment of your application configured with your clients LDAP running in intranet with Active Directory, another perhaps deployed on cloud using social login, and another maybe with a different auth provider all together B2C/Cognito/Auth0. &lt;a href="https://www.keycloak.org/docs/7.0/server_admin/#_kerberos" rel="noopener noreferrer"&gt;More info on Kerberos integration&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Configurable with a wide variety of databases
&lt;/h3&gt;

&lt;p&gt;Since Keycloak works on top of JDBC, it can be configured to use any database that has JDBC driver, which is a wide range of databases, including Postgresql, SQL Server and MySql.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authorisation services
&lt;/h3&gt;

&lt;p&gt;In addition to the standards based protocols, Keycloak provides a number of additional features and one of these is authorisation services. It gives you fine grained control on permissions that can be allocated on resources from the admin console. These permissions are exposed to the resource server as a set of RESTful APIs. &lt;a href="https://www.keycloak.org/docs/latest/authorization_services/" rel="noopener noreferrer"&gt;Docs here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Account Management Console
&lt;/h3&gt;

&lt;p&gt;Keycloak has a built in account management console that can be accessed by every logged in user. You could redirect users to their account management console from the client application where they can update their profile information, change password, check session history etc. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmi2rpn1sbvlo97s9yr2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmi2rpn1sbvlo97s9yr2.png" alt="Account Management Console"&gt;&lt;/a&gt; &lt;br&gt;
Having Keycloak provide the account management functionality is great since the OIDC provider is the custodian of this information. Like all other user interface elements in Keycloak, you can customise the Account Management Console anyway you like.&lt;/p&gt;

&lt;h3&gt;
  
  
  Support for wide range of external Identity Providers
&lt;/h3&gt;

&lt;p&gt;If you want to provide users options to login with the popular platforms such as Facebook, GitHub etc, Keycloak supports a wide range of external identity providers including any provider that supports OpenID Connect.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdvx0fh2k5sumhpyv8jo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdvx0fh2k5sumhpyv8jo.png" alt="Identity Providers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So in conclusion I would highly recommend you check out Keycloak for the following project types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are creating a new application and you need an identity solution.&lt;/li&gt;
&lt;li&gt;You have an existing application with and existing users database that is not OAuth2 or OpenID Connect and you'd like to create an OpenID Connect solution on top of the existing database.&lt;/li&gt;
&lt;li&gt;You want to create a multi-tenant application. Multi-tenancy can be achieved via realms or groups, based on your requirements.&lt;/li&gt;
&lt;li&gt;You host different instances of you application and would like to provide different types of Authentication for these instances based on your client requirements, eg. one with custom Storage SPI reading/writing to/from existing database, one with federated login with Microsoft and Google, One with simple username and password based authentication, etc.&lt;/li&gt;
&lt;li&gt;You need to provide windows integrated or Active Directory based authentication. &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>keycloak</category>
      <category>openidconnect</category>
      <category>oauth2</category>
    </item>
    <item>
      <title>AWS Cognito Hosted UI cannot be customised!</title>
      <dc:creator>Kayes Islam</dc:creator>
      <pubDate>Thu, 03 Jun 2021 14:06:42 +0000</pubDate>
      <link>https://dev.to/kayesislam/aws-cognito-hosted-ui-is-disappointing-3c93</link>
      <guid>https://dev.to/kayesislam/aws-cognito-hosted-ui-is-disappointing-3c93</guid>
      <description>&lt;p&gt;I'm currently investigating which auth provider I should use for my new web-api project. The requirements are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We need an OIDC solution with Authorization Code Flow with PKCE as we will have third party client applications (SPA/Mobile) developed by external vendors.&lt;/li&gt;
&lt;li&gt;We need to give users options to login using an existing external OIDC provider.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are quite a generic set of requirements that are commonly available in most OIDC providers. It was also quite easy to set-up in AWS Cognito as I expected. After everything is configured my login page looks like below:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9321qs57--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6yul54aahzl7t1l95dwr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9321qs57--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6yul54aahzl7t1l95dwr.png" alt="Screenshot Cognito"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only problem is... &lt;strong&gt;you can't customize the UI&lt;/strong&gt;. You can change some aspects, but only a handful of styles and colours (&lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-ui-customization.html"&gt;see here&lt;/a&gt;). But what if you want to change the text "Sign in with your corporate ID". As it stands today, you can't.&lt;/p&gt;

&lt;p&gt;The screenshot above is what AWS calls the "Hosted UI". If you are doing a Authorization Code Flow with PKCE then you need a hosted UI where the client application can redirect to. And if you're using a hosted UI 90% of the time you'd like to theme it to suite your brand needs. In fact, other than some demo application, I think any hosted UI by the OIDC providers should be themable.&lt;/p&gt;

&lt;p&gt;Azure B2C is superior in this regard, they allow ways to fully customize your hosted pages. &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory-b2c/customize-ui-with-html?pivots=b2c-user-flow"&gt;See here&lt;/a&gt; for more information.information.&lt;/p&gt;

&lt;p&gt;So if you're considering AWS Cognito for an identity solution and plan to use standard OIDC flows for public apps, keep that in mind. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Serverless Microservices in Asp.net with AWS API Gateway</title>
      <dc:creator>Kayes Islam</dc:creator>
      <pubDate>Wed, 02 Jun 2021 08:43:52 +0000</pubDate>
      <link>https://dev.to/kayesislam/serverless-microservices-in-asp-net-with-aws-api-gateway-106h</link>
      <guid>https://dev.to/kayesislam/serverless-microservices-in-asp-net-with-aws-api-gateway-106h</guid>
      <description>&lt;p&gt;For the project I am currently working on, I have been introduced to a whole array of services provided by AWS. We are going to embark on creating serverless Web APIs in AWS Lambda and Api Gateway. There are a few ways to achieve this and we needed to evaluate which way would work the best for our solution. &lt;/p&gt;

&lt;h1&gt;
  
  
  Lambda Functions
&lt;/h1&gt;

&lt;p&gt;One of the AWS serverless project templates provided by Amazon.Lambda.Templates has straight up lambda functions written in C# like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Functions
{
    public APIGatewayProxyResponse Get(
        APIGatewayProxyRequest request,
        ILambdaContext context
    )
    {
        context.Logger.LogLine("Get Request\n");
        var response = new APIGatewayProxyResponse
        {
            StatusCode = (int)HttpStatusCode.OK,
            Body = "Hello AWS Serverless",
            Headers = new Dictionary&amp;lt;string, string&amp;gt;
            {
                { "Content-Type", "text/plain"}
            }
        };


        return response;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is then put together with a SAM template file to define the AWS API Gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; "GetLambda": {
   "Type": "AWS::Serverless::Function",
   "Properties": {
     "Handler": "AwsServerless.Lambda::AwsServerless.Lambda.Functions::Get",
     "Runtime": "dotnetcore3.1",
     "CodeUri": "",
     "MemorySize": 256,
     "Timeout": 30,
     "Role": null,
     "Policies": [
       "AWSLambdaBasicExecutionRole"
     ],
     "Events": {
       "RootGet": {
         "Type": "Api",
         "Properties": {
           "Path": "/",
           "Method": "GET"
         }
       }
     }
   }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates an API endpoint that invokes the Get() method of our Function class when a GET request event occurs on our API's path "/".&lt;br&gt;
For local development, it comes with a Mock Lambda Test Tool. So if you hit F5 on your Visual Studio it opens this on localhost:5050:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez3bhpkdx91wkp34g4w4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez3bhpkdx91wkp34g4w4.png" alt="Mock Lambda Test Tool Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tool forwards the request to the lambda so that it could be executed/debugged with test JSON data in the local development environment. You can also invoke the tool from the command line without the UI and pass in a payload file. &lt;br&gt;
One thing to say here is that I'm quite unimpressed that there's no way to debug the lambda as an API service so that requests to a localhost:port endpoint are forwarded to the designated lambda. As a full stack developer, one of the common workflows for me is to open the API project in Visual Studio, open the client app project in VS Code and run the entire stack together. I didn't easily find any way to do that with a lambda project for .net. There's step through debugging available using AWS provided sam command line tool for nodejs, python and golang, but the documentation is missing for .net.&lt;br&gt;
Another issue here is that there's a lot of boilerplate code that we will need to put together for services we take for granted out of the box when we start-up a basic asp.net core project - CORS, JWT Auth, Authorization, HTTPS Redirection, Model Binding. None of this is present here. Sure how hard is it to hook it up together in a base class, but still it's work that needs to be done here.&lt;br&gt;
Using the lambda template straight out of the box also means your code base is strongly tied to AWS Lambda, not platform agnostic.&lt;/p&gt;
&lt;h1&gt;
  
  
  Asp.net Core
&lt;/h1&gt;

&lt;p&gt;Another project template that is provided by the Amazon.Lambda.Templates is an Asp.net core project configured to run as one lambda. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wi3k8sjtyzyxpid6m4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wi3k8sjtyzyxpid6m4v.png" alt="Project Outline Monolity"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are two notable files here: LocalEntryPoint.cs and LambdaEntryPoint.cs. LocalEntyPoint has the typical asp.net core main function for when you want to run it locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; public class LocalEntryPoint
 {
     public static void Main(string[] args)
     {
         CreateHostBuilder(args).Build().Run();
     }


     public static IHostBuilder CreateHostBuilder(string[] args) =&amp;gt;
         Host.CreateDefaultBuilder(args)
             .ConfigureWebHostDefaults(webBuilder =&amp;gt;
             {
                 webBuilder.UseStartup&amp;lt;Startup&amp;gt;();
             });
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;LambdaEntryPoint derives from APIGatewayProxyFunction which ensures that for each API gateway call the web-api's startup is invoked and the API Gateway request is marshalled into Asp.net core's request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; public class LambdaEntryPoint : 
    Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
 {
     protected override void Init(IWebHostBuilder builder)
     {
         builder
             .UseStartup&amp;lt;Startup&amp;gt;();
     }


     protected override void Init(IHostBuilder builder)
     {
     }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SAM template then uses a &lt;code&gt;/{proxy+}&lt;/code&gt; path to ensure that all requests to the root of the Api Gateway just invoke the Asp.net core application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; "AspNetCoreFunction": {
   "Type": "AWS::Serverless::Function",
   "Properties": {
     "Handler": "AWSServerless.Aspnet::AWSServerless.Aspnet.LambdaEntryPoint::FunctionHandlerAsync",
     "Runtime": "dotnetcore3.1",
     "CodeUri": "",
     "MemorySize": 256,
     "Timeout": 30,
     "Role": null,
     "Policies": [
       "AWSLambda_FullAccess"
     ],
     "Events": {
       "ProxyResource": {
         "Type": "Api",
         "Properties": {
           "Path": "/{proxy+}",
           "Method": "ANY"
         }
       },
       "RootResource": {
         "Type": "Api",
         "Properties": {
           "Path": "/",
           "Method": "ANY"
         }
       }
     }
   }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this configuration that routing is handled by asp.net core, not Api Gateway. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzr0lln5rw39yqmswdbh3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzr0lln5rw39yqmswdbh3.png" alt="Monolyth Lambda Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This configuration is familiar to any asp.net developer, which means new developers assigned to the project can hit the ground running. Full stack debug workflow I mentioned earlier is also a great advantage. Comes with all the benefits of Asp.net core, microsoft driven standard framework, available middlewares, libraries, community support and all the rest of it.&lt;br&gt;
The solution is also platform agnostic. All we need to do is write an entrypoint for Azure Functions or Google Cloud Function and the solution is potentially deployable on these platforms.&lt;br&gt;
The problem here is that this is a lambda monolith and not quite the microservices we are opting for. The benefits of microservices are lost here. Loading a lambda monolith would also have some performance impact.&lt;br&gt;
Another point to note here is that this is not a traditional asp.net core app, different environment, different lifecycle, hence some components won't work. For example, you won't be able to host SignalR, or a scheduler component as you could on your traditional asp.net core app. If you are investing into AWS however, you are probably looking at replacing these components with AWS provided services anyway, but it's just something to keep in mind.&lt;/p&gt;
&lt;h1&gt;
  
  
  Other Frameworks
&lt;/h1&gt;

&lt;p&gt;We did have a look at some other similar frameworks that could be used. &lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://nancyfx.org/" rel="noopener noreferrer"&gt;Nancy&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;A web framework similar to Asp.net core, with possibly less plumbing. Although it lacks the support and familiarity as Asp.net core does, it is indeed a very promising framework for microservices that I am keeping my eye on.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://www.serverless.com/" rel="noopener noreferrer"&gt;Serverless Framework&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Another very promising framework that enables writing serverless microservices in a platform agnostic way. At a first glance, I found most of the examples and libraries are for nodejs. I'm sure it has the libraries that provide sufficient middlewares to create a Restful API, but at a first glance, it just didn't give us the confidence for .net development.&lt;/p&gt;
&lt;h1&gt;
  
  
  Our Pick
&lt;/h1&gt;

&lt;p&gt;We decided to stick with the Asp.net core framework, but rather than having one monolith web-api, we decided to break it up into multiple web-api projects, each having their own Startup. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffizp5jfky90l3lwo6ptg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffizp5jfky90l3lwo6ptg.png" alt="Project Outline - Microservices"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a shared Infrastructure where we can encapsulate start-up behaviour common to all services. There's a LocalDev project which is the only place we have a LocalEntryPoint. This is set as the start-up project for local development only, not deployed to AWS. This project doesn't have any controllers. The Starup may have some extra configuration to set-up local dev environment. For example you may want to use Lambda Authorizer in production environment, but for local-dev you could enable Auth middleware.&lt;br&gt;
The other projects, each focused on a particular service: customers, orders and products. Each of these projects potentially deals with one type of resource (or related sub-resource). These projects have a Startup and a LambdaEntryPoint each as they will be deployed as to run as Lambda behind API Gateway.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fta4c96z51v2nrlia8mox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fta4c96z51v2nrlia8mox.png" alt="Microservices Asp.net Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The SAM templates then ensure that for a given base path, we invoke the correct LambdaEntryPoint. Below is an example for just the definition for product service as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; "ProductsServiceLambda": {
   "Type": "AWS::Serverless::Function",
   "Properties": {
     "Handler": "AWSServerlessDemo.Aspnet::AWSServerlessDemo.Products.LambdaEntryPoint::FunctionHandlerAsync",
     "Runtime": "dotnetcore3.1",
     "CodeUri": "./AWSServerlessDemo.Products/",
     "MemorySize": 256,
     "Timeout": 30,
     "Role": null,
     "Policies": [
       "AWSLambda_FullAccess"
     ],
     "Events": {
       "ProductsProxyResource": {
         "Type": "Api",
         "Properties": {
           "Path": "/products/{proxy+}",
           "Method": "ANY"
         }
       },
       "ProductsRootResource": {
         "Type": "Api",
         "Properties": {
           "Path": "/products/",
           "Method": "ANY"
         }
       }
     }
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note here that we're setting the &lt;code&gt;"CodeUri": "./AWSServerlessDemo.Products/"&lt;/code&gt;. This ensures that when the dotnet lambda tool will build and deploy just the source code for &lt;code&gt;AWSServerlessDemo.Products&lt;/code&gt;, keeping the size of the deployment to a minimum, a contributing factor to lambda performance.&lt;/p&gt;

&lt;h1&gt;
  
  
  Future of Asp.net as Microservices’ Framework
&lt;/h1&gt;

&lt;p&gt;.Net Core 5 has introduced some promising new features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/" rel="noopener noreferrer"&gt;C# Source Generators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/app-trimming-in-net-5/" rel="noopener noreferrer"&gt;Member-Level Trimming&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are experimental at this stage but have real potential. Currently the asp.net core lifecycle has a lot of dependency on reflection, slowing down the start-up time. But imagine the source generators replacing all the code dependent on reflection, then member level trimming reducing app size down to only the methods that are called! I'm excited to see how it unfolds!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>microservices</category>
      <category>aspnet</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
