diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8844870 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Open Harbor + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/OpenHarbor.JwtTokenManager.Abstractions/HttpClientExtensions.cs b/OpenHarbor.JwtTokenManager.Abstractions/HttpClientExtensions.cs new file mode 100644 index 0000000..9e4ce70 --- /dev/null +++ b/OpenHarbor.JwtTokenManager.Abstractions/HttpClientExtensions.cs @@ -0,0 +1,12 @@ +using System.Net.Http.Headers; + +namespace OpenHarbor.JwtTokenManager.Abstractions; + +public static class HttpClientExtensions +{ + public static HttpClient SetJwtAccessToken(this HttpClient httpClient, JwtTokenManagerResult token) + { + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token.TokenType.ToString(), token.AccessToken); + return httpClient; + } +} \ No newline at end of file diff --git a/OpenHarbor.JwtTokenManager.Abstractions/OpenHarbor.JwtTokenManager.Abstractions.csproj b/OpenHarbor.JwtTokenManager.Abstractions/OpenHarbor.JwtTokenManager.Abstractions.csproj index 80d8a67..aeb3265 100644 --- a/OpenHarbor.JwtTokenManager.Abstractions/OpenHarbor.JwtTokenManager.Abstractions.csproj +++ b/OpenHarbor.JwtTokenManager.Abstractions/OpenHarbor.JwtTokenManager.Abstractions.csproj @@ -6,6 +6,10 @@ enable Mathias Beaulieu-Duncan https://gravatar.com/avatar/9cecda5822fc5d4d2e61ec03da571b3d?size=256 + https://git.openharbor.io/Open-Harbor/dotnet-jwt-token-manager + git + true + MIT diff --git a/OpenHarbor.JwtTokenManager/JwtTokenManagerService.cs b/OpenHarbor.JwtTokenManager/JwtTokenManagerService.cs index f344f56..c978798 100644 --- a/OpenHarbor.JwtTokenManager/JwtTokenManagerService.cs +++ b/OpenHarbor.JwtTokenManager/JwtTokenManagerService.cs @@ -32,31 +32,29 @@ public class JwtTokenManagerService(JwtTokenManagerOptions options, IHttpClientF var client = httpClientFactory.CreateClient(); - var formContent = new FormUrlEncodedContent(new[] - { + var formContent = new FormUrlEncodedContent([ new KeyValuePair("grant_type", "client_credentials"), new KeyValuePair("client_id", options.ClientId), new KeyValuePair("client_secret", options.ClientSecret), - new KeyValuePair("scopes", string.Join(" ", options.Scopes)) - }); + new KeyValuePair("scopes", string.Join(" ", _scopes)) + ]); var request = new HttpRequestMessage(HttpMethod.Post, options.TokenEndpoint) { Content = formContent }; + request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var response = await client.SendAsync(request, cancellationToken); - var t = await response.Content.ReadAsStringAsync(cancellationToken); - response.EnsureSuccessStatusCode(); var tokenResponse = await response.Content.ReadFromJsonAsync(SnakeCaseOptions, cancellationToken); if (tokenResponse == null) { - throw new InvalidOperationException("Failed to deserialize the response content."); + throw new InvalidOperationException("Failed to deserialize the token response content."); } var parsedResult = Enum.TryParse(tokenResponse.TokenType, out var tokenType); diff --git a/OpenHarbor.JwtTokenManager/OpenHarbor.JwtTokenManager.csproj b/OpenHarbor.JwtTokenManager/OpenHarbor.JwtTokenManager.csproj index c74dba5..a4d6e4e 100644 --- a/OpenHarbor.JwtTokenManager/OpenHarbor.JwtTokenManager.csproj +++ b/OpenHarbor.JwtTokenManager/OpenHarbor.JwtTokenManager.csproj @@ -6,6 +6,10 @@ enable Mathias Beaulieu-Duncan https://gravatar.com/avatar/9cecda5822fc5d4d2e61ec03da571b3d?size=256 + https://git.openharbor.io/Open-Harbor/dotnet-jwt-token-manager + git + true + MIT diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..cae1551 --- /dev/null +++ b/readme.md @@ -0,0 +1,69 @@ +# Lightweight library allowing to manage access token its lifetime with caching capability for services accounts with the oauth2 protocol + +# Installing Nuget + +> Install nuget package to your awesome project. + +| Full Version | NuGet | NuGet Install | +|-----------------------------------------| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |----------------------------------------------------------------------------:| +| OpenHarbor.JwtTokenManager | [![NuGet](https://img.shields.io/nuget/v/OpenHarbor.JwtTokenManager.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/OpenHarbor.JwtTokenManager/) | ```PM> Install-Package OpenHarbor.JwtTokenManager``` | +| OpenHarbor.JwtTokenManager.Abstractions | [![NuGet](https://img.shields.io/nuget/v/OpenHarbor.JwtTokenManager.Abstractions.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/OpenHarbor.JwtTokenManager.Abstractions/) | ```PM> Install-Package OpenHarbor.JwtTokenManager.Abstractions``` | + +# How to use + +> appsettings.json + +```json +{ +"JwtTokenManager": { + "TokenEndpoint": "", + "ClientId": "", + "ClientSecret": "", + "Scopes": [] + } +} +``` + +> Program.cs + +```csharp +builder.Services.AddHttpClient(); +builder.Services.AddMemoryCache(); // use the IMemoryCache provider you want + +builder.Services.AddJwtTokenManager(builder.Configuration, "JwtTokenManager"); +``` + +> Program.cs with deeper configurations + +```csharp +builder.Services.AddHttpClient(); + +builder.Services.AddJwtTokenManager(builder.Configuration, "JwtTokenManager", options => +{ + options.Cache(cacheOptions => + { + cacheOptions.ExpirationOffset = 30; // 15 by default + }, + // optional to configure your own IMemoryCache provider for the token management + provider => provider.GetRequiredService()); + + options.Configuration(overrideConfiguration => + { + overrideConfiguration.Scopes = ["offline_access"]; + }); +}); +``` + +> Use the JwtTokenManager + +```csharp +public class MyService(HttpClient httpClient, IJwtTokenManagerService jwtTokenManagerService) +{ + public async Task DoActionAsync(CancellationToken cancellationToken) { + + var tokenResult = await jwtTokenManagerService.GetTokenAsync(cancellationToken); + httpClient.SetJwtAccessToken(tokenResult); + ... + } +} +``` \ No newline at end of file