{"id":14854,"date":"2022-02-21T12:03:42","date_gmt":"2022-02-21T11:03:42","guid":{"rendered":"https:\/\/www.centigrade.de\/?post_type=blog&#038;p=14854"},"modified":"2022-02-24T14:08:45","modified_gmt":"2022-02-24T13:08:45","slug":"how-to-engage-graphql-net-and-react-together-part-ii-veda-versum-backend-authentication","status":"publish","type":"blog","link":"https:\/\/www.centigrade.de\/en\/blog\/how-to-engage-graphql-net-and-react-together-part-ii-veda-versum-backend-authentication\/","title":{"rendered":"How to engage GraphQL, .Net and React together: Part II. Veda Versum backend authentication."},"content":{"rendered":"<blockquote>\r\n<p>&nbsp;<\/p>\r\n<p><em>&#8220;If you optimize everything, <\/em><em>you will always be unhappy&#8221; &#8211; \u00a0<\/em><a href=\"https:\/\/en.wikipedia.org\/wiki\/Donald_Knuth\">Donald Knuth<\/a><\/p>\r\n<\/blockquote>\r\n<p>Having a good tool allows you to complete tasks effectively and enjoy the process. Twice the fun to develop the tool yourself \ud83d\ude42<\/p>\r\n<p>Hi, It\u2019s <a href=\"https:\/\/www.centigrade.de\/de\/unternehmen\/team#mikhail.shabanov\">Mikhail<\/a> from Centigrade again. And let\u2019s continue to build our tool &#8211; knowledge base called <strong>Veda Versum<\/strong>. This is my second article in the series \u201cHow to engage GraphQL, .Net and React together\u201d. In the <a href=\"https:\/\/www.centigrade.de\/en\/blog\/how-to-engage-graphql-net-and-react-together-part-i\/\">Previous article<\/a> we have defined our target application, requirements and architecture. We have also chosen the .Net 6 for backend with <a href=\"https:\/\/github.com\/ChilliCream\/hotchocolate\">hot chocolate<\/a> library for <a href=\"https:\/\/graphql.org\/\">GraphQL<\/a> API and <a href=\"https:\/\/reactjs.org\/\">React<\/a> as the UI framework. And we have created the <a href=\"https:\/\/github.com\/Centigrade\/vedaversum\">backend application scaffold<\/a>. Now it\u2019s time to give life to our backend.<\/p>\r\n<p>Today we will add Authentication to backend. We will define and implement the data persistence for our application. We will talk about GraphQL <em>resolvers<\/em> and <em>data loaders<\/em> and will say a couple of words about testing.<\/p>\r\n<p>Let\u2019s get it started! \ud83d\ude09<!--more--><\/p>\r\n<h2>1.\u00a0\u00a0 Authentication and Authorization<\/h2>\r\n<p>We have already discussed in the previous article that each user can open application, create some knowledge cards, read cards and see other users who are being online. Sure, our <strong>Veda Versum<\/strong> application is supposed to know each user personally :-). As you already know, the common way to \u201cshow yourself\u201d in the IT world is \u00a0<strong>to log into<\/strong> the system. Yep, to do this you should have an account with login and password. Nothing new. We have to provide the same functionality for our brand new application. But we will not reinvent the wheel and will not implement the process of keeping users credentials by our own. We will use the standard protocol called <a href=\"https:\/\/oauth.net\/2\/\">OAuth 2<\/a>. According to this standard we are assumed to use already existing authentication server for our users. A lot of providers like Microsoft, Google, Twitter, Facebook and others support this protocol. So if you want to implement your own user management but don\u2019t want to run your own authentication server, you can use those. And one significant player in the field is <a href=\"https:\/\/auth0.com\/\">Auth0<\/a> which specializes on authentication services. But as far as our team uses GitLab for most of our projects, all of us have an account in GitLab. Therefore GitLab.com will be our OAuth provider. So <strong>Veda Versum<\/strong> user doesn\u2019t have to create one more account to login in <strong>Veda Versum<\/strong>, he or she can use already existing account in GitLab. Our application will redirect user to GitLab login page and after user enters his\/her login and password, he or she will be redirected back to our application but with some authentication token. And our application will operate only with this token.<\/p>\r\n<p>As far as our application has Frontend, Backend, and GitLab as OAuth 2 provider, authentication schema will look like this:<\/p>\r\n<div id=\"attachment_14873\" style=\"width: 708px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-14873\" class=\"size-full wp-image-14873\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild1-1.png\" alt=\"Authentication scheme\" width=\"698\" height=\"546\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild1-1.png 698w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild1-1-300x235.png 300w\" sizes=\"auto, (max-width: 698px) 100vw, 698px\" \/><p id=\"caption-attachment-14873\" class=\"wp-caption-text\">Fig. 1: Authentication scheme<\/p><\/div>\r\n<p>The whole scheme looks a bit complicated. I will try to explain all the details and guide you through all processes step by step.<\/p>\r\n<h3>1.1 GitLab Authentication mutation<\/h3>\r\n<p>First and foremost, we have to set up OAuth in the GitLab settings page. <a href=\"https:\/\/docs.gitlab.com\/ee\/integration\/oauth_provider.html#group-owned-applications\">Follow these instructions to create Group Owned Application.<\/a> As a result we will have <strong><em>Application Id<\/em><\/strong> and a <strong><em>secret<\/em><\/strong>. We will need them for next steps.<\/p>\r\n<p><a href=\"https:\/\/docs.gitlab.com\/ee\/api\/oauth2.html\">This is the link to Gitlab OAuth API<\/a> to implement the authentication. To implement steps 2 and 4 from <strong>Figure 1<\/strong> we need to call <strong><u>oauth\/authorize<\/u><\/strong> GitLab API method. This method will be called from UI. Later to implement steps 6 and 7 we must call method <strong><u>oauth\/token<\/u><\/strong>. And for steps 8 and 9 \u2013 to call method <strong><u>\/api\/v4\/user<\/u><\/strong>.<\/p>\r\n<p><strong>Frontend is not our goal for today, here we will focus on the backend part<\/strong>. To implement steps from 5 to 10 from <strong>Figure 1<\/strong> we must create a brand-new mutation in our GraphQL API which should retrieve GiltLabUser information. It will take <u>GitLab single-use Auth Code<\/u> as a parameter and return secured JWT token containing the user information. This mutation will incapsulate the implementation of steps 6 &#8211; 9 from <strong>Figure 1<\/strong>.<\/p>\r\n<p>To do that we have to change our project this way:<\/p>\r\n<ul>\r\n<li>Define 4 parameters in <em>json<\/em>;<\/li>\r\n<li>Create class <em>GitLabOauthSettings<\/em> which will read and hold values of these 4 parameters;<\/li>\r\n<li>Define <em>IGitlabOauthService<\/em> interface with 2 methods in it;<\/li>\r\n<li>Define <em>GitLabOauthService<\/em> class which implements interface and takes <em>Oauth app settings<\/em> and <em>GitLab http client<\/em> as dependency injection objects;<\/li>\r\n<li>Define new mutation with <em>GitLabAuthenticate<\/em> This mutation will use <em>IGitlabOauthService<\/em> as dependency injection object;<\/li>\r\n<li>Set up configuration, http client, GitLabOauthService and mutation in <em>cs<\/em>.<\/li>\r\n<\/ul>\r\n<p>The code base should look like this:<\/p>\r\n<div id=\"attachment_14884\" style=\"width: 442px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-14884\" class=\"size-full wp-image-14884\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild2-1.png\" alt=\"GitLab authentication mutation class diagram\" width=\"432\" height=\"301\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild2-1.png 432w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild2-1-300x209.png 300w\" sizes=\"auto, (max-width: 432px) 100vw, 432px\" \/><p id=\"caption-attachment-14884\" class=\"wp-caption-text\">Fig. 2: GitLab authentication mutation class diagram<\/p><\/div>\r\n<p>So, as Linus Torvalds said: \u201cTalk is cheap, show me the code\u201d.<\/p>\r\n<p>&nbsp;<\/p>\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\nappsettings.json:\r\n  &quot;GitLabOauth&quot;: {\r\n    &quot;BaseAddress&quot;: &quot;https:\/\/gitlab.example.com&quot;,\r\n    &quot;ClientId&quot;: &quot;FakeClientId&quot;,\r\n    &quot;Secret&quot;: &quot;FakeSecret&quot;,\r\n    &quot;JwtSecret&quot;: &quot;FakeJwtSecret&quot;\r\n  },\r\n\r\n<\/pre><\/div>\r\n\r\n\r\n<p>One tip regarding app settings. I\u2019m using <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/security\/app-secrets?view=aspnetcore-5.0&amp;tabs=windows\">app secrets<\/a> mechanism to keep sensitive data in the development machine instead of appsettings.json. Having this I\u2019m always debugging the code with real sensitive data and at the same time I will never commit them to the public repository.<\/p>\r\n\r\n\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nOAuthMutation.cs:\r\n        \/\/\/ &lt;summary&gt;\r\n        \/\/\/ This method accepts GitLab oauth code, and returns JWT token with GutLab user as claim\r\n        \/\/\/ &lt;\/summary&gt;\r\n        \/\/\/ &lt;param name=&quot;oauthCode&quot;&gt;OAuth code can be generated by this URL https:\/\/gitlab.example.com\/oauth\/authorize&lt;\/param&gt;\r\n        \/\/\/ &lt;remarks&gt;\r\n        \/\/\/ More info about GitLab OAuth https:\/\/docs.gitlab.com\/ee\/api\/oauth2.html\r\n        \/\/\/ &lt;\/remarks&gt;\r\n        public async Task&lt;string&gt; GitLabAuthenticate(string oauthCode)\r\n        {\r\n            try\r\n            {\r\n                var user = await _oauthService.GetUser(oauthCode);\r\n                if (user == null)\r\n                {\r\n                    throw new ApplicationException($&quot;Can not find GitLab user by code {oauthCode}&quot;);\r\n                }\r\n                return _oauthService.GenerateToken(user);\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                _logger.LogError(e,&quot;Authentication fails&quot;);\r\n                throw;\r\n            }\r\n        }\r\n\r\n<\/pre><\/div>\r\n\r\n\r\n<p>You can find the whole mutation class in the <a href=\"https:\/\/github.com\/Centigrade\/vedaversum\/blob\/main\/VedaVersum.Backend\/Api\/OAuthMutation.cs\">repository<\/a>. Here is the mutation method which is just calling two service methods \u2013 <strong>get user<\/strong> and <strong>generate JWT token<\/strong><\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/Centigrade\/vedaversum\/blob\/main\/VedaVersum.Backend\/OAuth\/GitLabOauthService.cs\">GitLabOauthService.cs<\/a><\/p>\r\n\r\n\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n        \/\/\/ &lt;inheritdoc \/&gt;\r\n        public string GenerateToken(User user)\r\n        {\r\n            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.JwtSecret));\r\n            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);\r\n            var serializedUser = JsonSerializer.Serialize(user);\r\n\r\n            \/\/ generate jwt token\r\n            var claims = new&#x5B;]\r\n            {\r\n                new Claim(ClaimTypes.Name, user.Name?? &quot;unknown&quot;),\r\n                new Claim(ClaimTypes.Email, user.Email?? &quot;unknown&quot;),\r\n                new Claim(ClaimTypes.UserData, serializedUser)\r\n            };\r\n\r\n            var token = new JwtSecurityToken(\r\n                issuer: JwtIssuer,\r\n                audience: JwtIssuer,\r\n                claims: claims,\r\n                expires: DateTime.Now.AddDays(30), \/\/ Token is valid for 1 month. Don&#039;t use this parameter in production!\r\n                signingCredentials: credentials);\r\n\r\n            return new JwtSecurityTokenHandler().WriteToken(token);\r\n        }\r\n\r\n        \/\/\/ &lt;inheritdoc \/&gt;\r\n        public async Task&lt;User?&gt; GetUser(string oAuthCode)\r\n        {\r\n            var token = await GetAccessToken(oAuthCode);\r\n            return await GetGitLabUser(token);\r\n        }\r\n\r\n        private async Task&lt;string&gt; GetAccessToken(string oAuthCode)\r\n        {\r\n            var parameters = new Dictionary&lt;string, string&gt;\r\n            {\r\n                { &quot;client_id&quot;, _settings.ClientId }, \r\n                { &quot;client_secret&quot;, _settings.Secret },\r\n                { &quot;code&quot;, oAuthCode },\r\n                { &quot;grant_type&quot;, &quot;authorization_code&quot; },\r\n                { &quot;redirect_uri&quot;, &quot;https:\/\/localhost:5001&quot; }\r\n            };\r\n            var encodedContent = new FormUrlEncodedContent(parameters!);\r\n\r\n            var client = _httpClientFactory.CreateClient(GitLabHttpClientName);\r\n\r\n            var url = $&quot;{_settings.BaseAddress}\/oauth\/token&quot;;\r\n\r\n            var response = await client.PostAsync(url, encodedContent).ConfigureAwait(false);\r\n            response.EnsureSuccessStatusCode();\r\n\r\n            await using var responseStream = await response.Content.ReadAsStreamAsync();\r\n            var authTokenResponse = await JsonSerializer.DeserializeAsync&lt;OAuthTokenResponse?&gt;(responseStream);\r\n\r\n            if(string.IsNullOrEmpty(authTokenResponse?.AccessToken))\r\n            {\r\n                throw new ApplicationException($&quot;Can not get access_token from url &#039;{_settings.BaseAddress}&#039; and Auth code &#039;{oAuthCode}&#039;&quot;);\r\n            }\r\n            return authTokenResponse.AccessToken;\r\n        }\r\n\r\n        private async Task&lt;User?&gt; GetGitLabUser(string token)\r\n        {\r\n            string url = $&quot;{_settings.BaseAddress}\/api\/v4\/user&quot;;\r\n\r\n            var client = _httpClientFactory.CreateClient(GitLabHttpClientName);\r\n            client.DefaultRequestHeaders.Authorization\r\n                = new AuthenticationHeaderValue(&quot;Bearer&quot;, token);\r\n            client.DefaultRequestHeaders.Add(&quot;User-Agent&quot;, &quot;VedaVersum&quot;);\r\n\r\n            var response = await client.GetAsync(url);\r\n\r\n            response.EnsureSuccessStatusCode();\r\n            \r\n            await using var responseStream = await response.Content.ReadAsStreamAsync();\r\n            return await JsonSerializer.DeserializeAsync&lt;User?&gt;(responseStream);\r\n        }\r\n\r\n<\/pre><\/div>\r\n\r\n\r\n<p>You can find the whole service class in the <a href=\"https:\/\/github.com\/Centigrade\/vedaversum\/tree\/main\/VedaVersum.Backend\">repository<\/a>. Here are three main methods:<\/p>\r\n\r\n\r\n\r\n<p>The first method calls GitLab API to get access token. We will need this token in the second method \u2013 to get GitLab user from GitLab API. And the third method generates JWT token with user information secured by SHA algorithm with some secret key stored in application setting.<\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/github.com\/Centigrade\/vedaversum\/blob\/main\/VedaVersum.Backend\/Startup.cs\">startup.cs<\/a>:<\/p>\r\n\r\n\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            \/\/ GitLab authorization configuration\r\n            var gitLabOauthConfig = new GitLabOauthSettings();\r\n            Configuration.GetSection(&quot;GitLabOauth&quot;).Bind(gitLabOauthConfig);\r\n            services.AddSingleton(gitLabOauthConfig);\r\n\r\n            \/\/ GitLab authorization\r\n            services.AddHttpClient(GitLabOauthService.GitLabHttpClientName);\r\n            services.AddTransient&lt;IGitLabOauthService, GitLabOauthService&gt;();\r\n            services\r\n                .AddGraphQLServer()\r\n                .AddInMemorySubscriptions()\r\n                .AddQueryType&lt;VedaVersumQuery&gt;()\r\n                    .AddType&lt;VedaVersumCardObjectType&gt;()\r\n                .AddMutationType(d =&gt; d.Name(&quot;Mutation&quot;))\r\n                    .AddType&lt;OAuthMutation&gt;() \/\/ Register new OAuth Mutation in the GraphQL API\r\n                    .AddType&lt;VedaVersumMutation&gt;()\r\n                .AddSubscriptionType&lt;VedaVersumSubscription&gt;();\r\n       }\r\n\r\n<\/pre><\/div>\r\n\r\n\r\n<p>Here we are reading configuration from app settings and adding settings to DI container. We push new <em>GitLabOauthService<\/em> to DI container and register new <em>OAuthMutation<\/em> in the GraphQL API<\/p>\r\n\r\n\r\n\r\n<p>Now our service is ready to generate JWT tokens. If you take a look to <strong>Figure 1<\/strong>, you will notice that we still need to get GitLab single-use Authentication code somewhere. These are steps 2, 3 and 4 to be managed by Frontend in the future. But as far as we don\u2019t have frontend yet, we will do these steps manually. We should open the browser and send this url to GitLab:<\/p>\r\n\r\n\r\n\r\n<p><em>https:\/\/gitlab.<span style=\"color: #ff0000;\">example<\/span>.com\/oauth\/authorize?client_id=<span style=\"color: #ff0000;\">APP_ID<\/span>&amp;redirect_uri=https:\/\/localhost:5001&amp;response_type=code&amp;state=<span style=\"color: #ff0000;\">TEMPORARY_STATE<\/span>&amp;scope=read_user<\/em><\/p>\r\n\r\n\r\n\r\n<p>You should replace 3 parameters:<\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li>gitlab.example.com to your gitlab server URL<\/li>\r\n<li>APP_ID to your own Application Id which you received when creating <a href=\"https:\/\/docs.gitlab.com\/ee\/integration\/oauth_provider.html#group-owned-applications\">GitLab group owned application<\/a><\/li>\r\n<li>TEMPORARY_STATE can be any string. I\u2019m using GUID generator to generate it.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<p>When you navigate to this url, you will be redirected to GitLab authentication page. And after successful login, you will be redirected to https:\/\/localhost:5001 which does not exist yet. All you need at the moment will be in the browser address line:<\/p>\r\n\r\n\r\n\r\n<p><em>https:\/\/localhost:5001\/?code=<span style=\"color: #ff0000;\">4debdf62d4458dbd02be661661506c869582232b0bf7632d5e10e74045318eb0<\/span>&amp;state=29aa0c42-58d0-4129-9d76-33094fa56401<\/em><\/p>\r\n\r\n\r\n\r\n<p>We will use this code in our Authentication mutation. When you start <strong>VedaVersum<\/strong> application, there will be shown GraphQL <a href=\"https:\/\/chillicream.com\/docs\/bananacakepop\">BananaCakePop<\/a> IDE, where you can call the mutation:<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"698\" height=\"265\" class=\"wp-image-14882\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild3-1.png\" alt=\"Authentication mutation execution\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild3-1.png 698w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild3-1-300x114.png 300w\" sizes=\"auto, (max-width: 698px) 100vw, 698px\" \/>\r\n<figcaption>Fig. 3: Authentication mutation execution<\/figcaption>\r\n<\/figure>\r\n\r\n\r\n\r\n<p>If you did everything right, the mutation will return you the JWT token back. You can test this token using <a href=\"https:\/\/jwt.io\/\">https:\/\/jwt.io\/<\/a><\/p>\r\n\r\n\r\n\r\n<p>&nbsp;<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"522\" height=\"378\" class=\"wp-image-14871\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild4-1.png\" alt=\"JWT token\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild4-1.png 522w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild4-1-300x217.png 300w\" sizes=\"auto, (max-width: 522px) 100vw, 522px\" \/>\r\n<figcaption>Figure 4. JWT token<\/figcaption>\r\n<\/figure>\r\n\r\n\r\n\r\n<p>That means we have the right token. In the future this token will be stored somewhere in the Frontend. And each time frontend calls queries or mutations in our GraphQL API, it should add this token as http header to each request to authenticate the user. But as far as we don\u2019t have frontend yet, let\u2019s keep this token somewhere in notepad. We will need it in the next chapter ?<\/p>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">1.2 Authorization by JWT token<\/h3>\r\n\r\n\r\n\r\n<p>We have already created mechanism to authenticate user and store user information as encrypted JWT token at Frontend. So far, so good ? Now it is time to secure our GraphQL API and allow only the users with valid JWT tokens to use its queries and mutations.<\/p>\r\n\r\n\r\n\r\n<p>Each http request in Asp.net core server goes through some \u201cpipeline\u201d. This pipeline has its own context. And developers can inject different \u201cmiddleware\u201d types into this pipeline and manipulate the context. Asp net core has <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/security\/?view=aspnetcore-6.0\">standard authorization mechanisms<\/a> which are implemented as middleware too. We have also added GraphQL server by <a href=\"https:\/\/chillicream.com\/docs\/hotchocolate\">ChilliCream<\/a> as middleware, which has its own context per each request.<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"698\" height=\"67\" class=\"wp-image-14867\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild5.png\" alt=\"Asp.net core pipeline\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild5.png 698w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild5-300x29.png 300w\" sizes=\"auto, (max-width: 698px) 100vw, 698px\" \/>\r\n<figcaption>Figure 5. Asp.net core pipeline<\/figcaption>\r\n<\/figure>\r\n\r\n\r\n\r\n<p>Firstly we need to inject our JWT authorization logic into standard Authentication middleware. Secondly we need to add User to GraphQL middleware context.<\/p>\r\n\r\n\r\n\r\n<p>To add JWT Token authentication as standard Asp.net Core middleware we need to add nuget packages \u201cMicrosoft.AspNetCore.Authentication.JwtBearer\u201d and \u201cSystem.IdentityModel.Tokens.Jwt\u201d to our project. And then set up Authentication service in the DI Container like this:<\/p>\r\n\r\n\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n            \/\/ Token validation\r\n            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\r\n                .AddJwtBearer(options =&gt;\r\n                {\r\n                    options.TokenValidationParameters = new TokenValidationParameters\r\n                    {\r\n                        ValidateIssuer = true,\r\n                        ValidateAudience = true,\r\n                        ValidateLifetime = true,\r\n                        ValidateIssuerSigningKey = true,\r\n                        ValidIssuer = GitLabOauthService.JwtIssuer,\r\n                        ValidAudience = GitLabOauthService.JwtIssuer,\r\n                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(gitLabOauthConfig.JwtSecret))\r\n                    };\r\n                });\r\n\r\n<\/pre><\/div>\r\n\r\n\r\n<p>Add Authentication and Authorization middleware in the <em>Configure<\/em> method:<\/p>\r\n\r\n\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n            app\r\n                .UseWebSockets()\r\n                .UseRouting()\r\n                .UseAuthentication() \/\/ Authentication middleware\r\n                .UseAuthorization() \/\/ Authorization middleware\r\n                .UseEndpoints(endpoints =&gt;\r\n                {\r\n                    endpoints.MapGraphQL();\r\n                });\r\n\r\n<\/pre><\/div>\r\n\r\n\r\n<p>Well, we have just implemented blocks number 1 and 2 from <strong>Figure 5<\/strong>.<\/p>\r\n\r\n\r\n\r\n<p>To add Authorization into GraphQL Server middleware, we have to add new nuget package \u201cHotChocolate.AspNetCore.Authorization\u201d. And to add authorization to the GraphQL DI setup in startup.cs:<\/p>\r\n\r\n\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n        services\r\n            .AddGraphQLServer()\r\n\t\u2026\r\n            .AddAuthorization()\r\n\r\n<\/pre><\/div>\r\n\r\n\r\n<p>After that we have to add [Authorize] attribute to the <em>VedaVersumQuery<\/em>, <em>VedaVersumMutation<\/em> and <em>VedaVersumSubscription<\/em> classes:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"409\" height=\"357\" class=\"wp-image-14880\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild6.png\" alt=\"Add [Authorize] attribute to the VedaVersumQuery\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild6.png 409w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild6-300x262.png 300w\" sizes=\"auto, (max-width: 409px) 100vw, 409px\" \/><\/figure>\r\n\r\n\r\n\r\n<p>Here we have implemented block number 3 from <strong>Figure 5<\/strong>.<\/p>\r\n\r\n\r\n\r\n<p>Now we can try to call any query or mutation without any authorization tokens:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"546\" height=\"308\" class=\"wp-image-14878\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild7.png\" alt=\"Authentication error for anonymous users\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild7.png 546w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild7-300x169.png 300w\" sizes=\"auto, (max-width: 546px) 100vw, 546px\" \/>\r\n<figcaption>Fig. 6: Authentication error for anonymous users<\/figcaption>\r\n<\/figure>\r\n\r\n\r\n\r\n<p>As you can see, anonymous users cannot use our GraphQL API anymore.<\/p>\r\n\r\n\r\n\r\n<p>But if we add the http header {\u201cAuthorization\u201d: \u201cBearer \u2026\u201d} with valid token to our request, mutation is executed as expected:<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"551\" height=\"296\" class=\"wp-image-14876\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild8-1.png\" alt=\"Normal mutation execution for authorized users\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild8-1.png 551w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild8-1-300x161.png 300w\" sizes=\"auto, (max-width: 551px) 100vw, 551px\" \/>\r\n<figcaption>Fig. 7: Normal mutation execution for authorized users<\/figcaption>\r\n<\/figure>\r\n\r\n\r\n\r\n<p>The last but not the least: if user is authorized, <strong><em>User <\/em><\/strong>object of <strong><em>PrincipalIdentity<\/em><\/strong> type will be added to the asp.net pipeline context. And this object will be accessible in all the middlewares after \u201cAuthorization\u201d middleware, including GraphQL Resolver at the block 4 (<strong>Figure 5<\/strong>). But in the Business Logic we need to operate the <strong><em>GitLabUser<\/em><\/strong> object with all the requested properties. We can convert that <strong><em>PrincipalIdentity<\/em><\/strong> into <strong><em>GitLabUser<\/em><\/strong> right in the resolver. But if we have a lot of resolvers, we have to make that conversion each time. It would be better to convert <strong><em>PrincipalIdentity<\/em><\/strong> into <strong><em>GitLabUser<\/em><\/strong> earlier in the pipeline and put converted <strong><em>GitLabUser<\/em><\/strong> object into the pipeline\u2019s context. And here is the example how we can do this in the level of block 3 (from <strong>Figure 5<\/strong>):<\/p>\r\n\r\n\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n        services\r\n            .AddGraphQLServer()\r\n\t\u2026\r\n            .AddAuthorization()\r\n            .AddHttpRequestInterceptor(\r\n                (context, executor, builder, ct) =&gt;\r\n                {\r\n                    \/\/ Deserializing GitLab user from JWT token data\r\n                    if(context.User != null)\r\n                    {\r\n                        var serializedUser = context.User.Claims.Where(c =&gt; c.Type == ClaimTypes.UserData)\r\n                            .Select(c =&gt; c.Value).SingleOrDefault();\r\n                        if(!string.IsNullOrEmpty(serializedUser))\r\n                        {\r\n                            var user = JsonSerializer.Deserialize&lt;User&gt;(serializedUser);\r\n                            builder.SetProperty(&quot;GitLabUser&quot;, user);\r\n                        }\r\n                    }\r\n                    return ValueTask.CompletedTask;\r\n                })\r\n            .ModifyRequestOptions(opt =&gt; opt.IncludeExceptionDetails = true);\r\n\r\n<\/pre><\/div>\r\n\r\n\r\n<p>This interceptor gets <strong><em>GitlabUser<\/em><\/strong> from <strong><em>PrincipalIdentity<\/em><\/strong> and put this object into context using key \u201cGitLabUser\u201d. Later we can use this object in any of our resolvers like this:<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1014\" height=\"696\" class=\"wp-image-14869\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild9.png\" alt=\"interceptor gets GitlabUser from PrincipalIdentity \" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild9.png 1014w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild9-300x206.png 300w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild9-768x527.png 768w\" sizes=\"auto, (max-width: 1014px) 100vw, 1014px\" \/><\/figure>\r\n\r\n\r\n\r\n<p>OK, we have added the full round of authentication and authorization to our backend using GitLab as OAuth 2 authentication provider. We have also made our GraphQL API fully secured.<\/p>\r\n\r\n\r\n\r\n<p>The last but not the least. We have created one of the most complicated parts of the program and the only way to test its capability is to \u00a0run the application and do all the necessary steps manually. But sometimes we need to check fast if everything works. And it is even better to test after each commit if we haven\u2019t broken anything. I have created the test project which uses <a href=\"https:\/\/nunit.org\/\">NUnit<\/a> testing framework and <a href=\"https:\/\/riptutorial.com\/moq\">Moq<\/a> library for creating mock objects. There is a test scenario where I\u2019m mocking the .Net HTTP client class and checking if Gitlab Web API methods are called with appropriate URIs, parameters and authorization tokens. You can check out the code in the <a href=\"https:\/\/github.com\/Centigrade\/vedaversum\/blob\/main\/VedaVersum.Test\/OAuthServiceTest.cs\">GitHub repository<\/a>. We will talk about unit tests in details in our next article.<\/p>\r\n\r\n\r\n\r\n<p>That\u2019s all for today :-). In the next article we will dive into the data persistency and GraphQL resolvers and Data loaders. See you! \ud83d\ude42<\/p>\r\n","protected":false},"author":66,"featured_media":0,"template":"","tags":[177,886,235,885,653,8,638],"class_list":["post-14854","blog","type-blog","status-publish","hentry","tag-net","tag-api","tag-csharp","tag-graphql","tag-react-en","tag-software-developers","tag-ux-engineering-en-2"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog\/14854","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog"}],"about":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/types\/blog"}],"author":[{"embeddable":true,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/users\/66"}],"version-history":[{"count":19,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog\/14854\/revisions"}],"predecessor-version":[{"id":14898,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog\/14854\/revisions\/14898"}],"wp:attachment":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/media?parent=14854"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/tags?post=14854"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}