Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System.Net.Mime;
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SimpleAuthentication.Auth0;
using SimpleAuthentication.JwtBearer;

namespace SimpleAuthentication.WebApi.Controllers;
Expand Down Expand Up @@ -58,10 +61,46 @@ public ActionResult<LoginResponse> Refresh(string token, bool validateLifetime =
var newToken = jwtBearerService.RefreshToken(token, validateLifetime, expiration);
return new LoginResponse(newToken);
}

[HttpPost]
[Route("auth0")]
public LoginResponseAuth0? LoginAuth0([FromServices] IAuth0Service auth0Service)
{
// Check for login rights...

// Add custom claims (optional).
var claims = new List<Claim>
{
new(ClaimTypes.GivenName, "Marco"),
new(ClaimTypes.Surname, "Minerva")
};

var token = auth0Service.ObtainTokenAsync(claims);
return JsonConvert.DeserializeObject<LoginResponseAuth0>(token.Result);
}
}

public record class LoginRequest(string UserName, string Password);

public record class LoginResponse(string Token);

public record class ValidationResponse(bool IsValid, User? User);
public record class ValidationResponse(bool IsValid, User? User);

public record class LoginResponseAuth0
{
[JsonProperty("access_token")]
public string Token { get; set; }

[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }

[JsonProperty("token_type")]
public string Type { get; set; }

public LoginResponseAuth0(string token, int expiresIn, string type)
{
this.Token = token;
this.ExpiresIn = expiresIn;
this.Type = type;
}
}
10 changes: 10 additions & 0 deletions samples/SimpleAuthentication.WebApi/Controllers/MeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ public class MeController : ControllerBase
[ProducesDefaultResponseType]
public ActionResult<User> GetWithBearer()
=> new User(User.Identity!.Name);

[Authorize(AuthenticationSchemes = "ApiKey")]
[HttpGet("authorize-apikey")]
public User GetWithApiKey()
=> new(User.Identity!.Name);

[Authorize(AuthenticationSchemes = "Auth0")]
[HttpGet("authorize-auth0")]
public User GetWithAuth0()
=> new("Auth0 default user");
}

public record class User(string? UserName);
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
11 changes: 10 additions & 1 deletion samples/SimpleAuthentication.WebApi/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"Authentication": {
"DefaultAuthenticationScheme": "Bearer", // Optional
"JwtBearer": {
"SchemeName": "Bearer", // Default Bearer
"SchemeName": "Bearer", // Default Bearer
"SecurityKey": "YKgsOiwvDLJe42dyyL3FkhlMAzZZ2Cmr0FTpyLsPE5DA2afd6NbbCV3d5oHDG2rVBaDHH540EUmrzXPPk2LnfanCdERl4apucmu2Ev5oVgN6dGCr8MMxXIIyTaNmmXHSsaONo75UkxQvFtsm9Qsnsz3VxuNzsoqrzqBQdsDvClo1LcrRNNcTdKcvceq1G57PZNxOWFS749wnsqq7r17a9vvinTdYME2umo7DRn8XUiwbdOajCehJfqipIjwbcuoCIrCwwMizKSiidw5KXU7koVvUSV0UH3o4TWHsVBnt5B1os6oPKtCQ63CPqlwHB5Pet4mzA2lhaFROZXbStpigaRJf3J6AOwZurMbo3LhzCpPW6KZwkixMpwCb82ekZvL0tmfQA2LeWDL2esZ9N4N8w8CzxrZt4gyEfywBwsoFohC0ydVznDpwbgCg05ktuczX3FFcsXEErwtY2wu0or0TSrUSnzIrYP26dOOUh4qREPJ7ZnZ5NoQjOMcXkiThdMuy", // Required
"Algorithm": "HS256", // Default HS256
"Issuers": [ "issuer" ], // Optional
Expand All @@ -21,6 +21,15 @@
// to validate the API Key.
//"ApiKeyValue": "f1I7S5GXa4wQDgLQWgz0",
"DefaultUserName": "ApiUser" // Required when ApiKeyValue is used
},
"Auth0":{
// This parameter are getteedtaken from https://auth0.com/ only for test
"SchemeName": "Auth0",
"Algorithm": "RS256",
"Domain": "https://dev-a6-vyksc.us.auth0.com", // The domain created on https://auth0.com/
"Audience": "https://github.com/micheletolve",
"ClientId": "ipSAr24nCse9QIAlpN6nm2sYdarlaVY5",
"ClientSecret": "dr-qxPyLT2O7eDzCdzal9CHAe-V7t-aouZWBsDNCUsCk6r-rOjrVRQtZ9zGL7wCT"
}
},
"Logging": {
Expand Down
38 changes: 38 additions & 0 deletions src/SimpleAuthentication/Auth0/Auth0Service.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using Microsoft.Extensions.Options;

namespace SimpleAuthentication.Auth0
{
internal class Auth0Service : IAuth0Service
{
private readonly Auth0Settings auth0Setting;

public Auth0Service(IOptions<Auth0Settings> auth0SettingOptions)
{
auth0Setting = auth0SettingOptions.Value;
}

public async Task<string> ObtainTokenAsync(IList<Claim>? claims = null)
{
string responseContent;
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(auth0Setting.Domain);
httpClient.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage(HttpMethod.Post, "/oauth/token");
request.Content = new StringContent("{\"client_id\":\"ipSAr24nCse9QIAlpN6nm2sYdarlaVY5\",\"client_secret\":\"dr-qxPyLT2O7eDzCdzal9CHAe-V7t-aouZWBsDNCUsCk6r-rOjrVRQtZ9zGL7wCT\",\"audience\":\"https://github.com/micheletolve\",\"grant_type\":\"client_credentials\"}",
Encoding.UTF8,
"application/json");

using (var responseMessage = await httpClient.SendAsync(request))
{
responseContent = await responseMessage.Content.ReadAsStringAsync();
}
return responseContent;
}
}
}
40 changes: 40 additions & 0 deletions src/SimpleAuthentication/Auth0/Auth0Settings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;

namespace SimpleAuthentication.Auth0
{
/// <summary>
/// Options class provides information needed to control Auth0 Authentication handler behavior.
/// </summary>
public class Auth0Settings
{
/// <summary>
/// Gets or sets The authentication scheme name (Default: Auth0).
/// </summary>
public string SchemeName { get; set; } = JwtBearerDefaults.AuthenticationScheme;

/// <summary>
/// Gets or sets the cryptographic algorithm that is used to generate the digital signature (Default: RS256).
/// </summary>
public string Algorithm { get; set; } = "RS256";

/// <summary>
/// Gets or sets the domain.
/// </summary>
public string Domain { get; set; } = null!;

/// <summary>
/// Gets or sets the valid audiences that will be used to check against the token's audience.
/// </summary>
public string Audience { get; set; } = null!;

/// <summary>
/// Gets or sets the client id.
/// </summary>
public string CilentId { get; set; } = null!;

/// <summary>
/// Gets or sets the client secret.
/// </summary>
public string CilentSecret { get; set; } = null!;
}
}
17 changes: 17 additions & 0 deletions src/SimpleAuthentication/Auth0/IAuth0Service.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Security.Claims;

namespace SimpleAuthentication.Auth0
{
/// <summary>
/// Provides methods for Auth0 Bearer generation and validation.
/// </summary>
public interface IAuth0Service
{
/// <summary>
/// Obtains a bearer token string from Auth0 provider.
/// </summary>
/// <param name="claims">The claims list.</param>
/// <returns></returns>
Task<string> ObtainTokenAsync(IList<Claim>? claims = null);
}
}
25 changes: 25 additions & 0 deletions src/SimpleAuthentication/SimpleAuthenticationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Microsoft.Net.Http.Headers;
using Microsoft.OpenApi.Models;
using SimpleAuthentication.ApiKey;
using SimpleAuthentication.Auth0;
using SimpleAuthentication.JwtBearer;
using SimpleAuthentication.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
Expand Down Expand Up @@ -64,6 +65,7 @@ public static ISimpleAuthenticationBuilder AddSimpleAuthentication(this Authenti
{
CheckAddJwtBearer(builder, configuration.GetSection($"{sectionName}:JwtBearer"));
CheckAddApiKey(builder, configuration.GetSection($"{sectionName}:ApiKey"));
CheckAddAuth0(builder, configuration.GetSection($"{sectionName}:Auth0"));

return new DefaultSimpleAuthenticationBuilder(configuration, builder);

Expand Down Expand Up @@ -134,6 +136,29 @@ static void CheckAddApiKey(AuthenticationBuilder builder, IConfigurationSection
options.DefaultUserName = settings.DefaultUserName;
});
}

static void CheckAddAuth0(AuthenticationBuilder builder, IConfigurationSection section)
{
var auth0Settings = section.Get<Auth0Settings>();
if (auth0Settings is null)
{
return;
}

ArgumentNullException.ThrowIfNull(auth0Settings.SchemeName, nameof(Auth0Settings.SchemeName));
ArgumentNullException.ThrowIfNull(auth0Settings.Domain, nameof(Auth0Settings.Domain));
ArgumentNullException.ThrowIfNull(auth0Settings.Audience, nameof(Auth0Settings.Audience));

builder.Services.Configure<Auth0Settings>(section);

builder.AddJwtBearer(auth0Settings.SchemeName, options =>
{
options.Authority = auth0Settings.Domain;
options.Audience = auth0Settings.Audience;
});

builder.Services.TryAddSingleton<IAuth0Service, Auth0Service>();
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using SimpleAuthentication.ApiKey;
using SimpleAuthentication.Auth0;
using SimpleAuthentication.JwtBearer;
using Swashbuckle.AspNetCore.SwaggerGen;

Expand All @@ -18,12 +19,14 @@ internal class AuthenticationOperationFilter : IOperationFilter
private readonly IAuthorizationPolicyProvider authorizationPolicyProvider;
private readonly JwtBearerSettings jwtBearerSettings;
private readonly ApiKeySettings apiKeySettings;
private readonly Auth0Settings auth0Settings;

public AuthenticationOperationFilter(IAuthorizationPolicyProvider authorizationPolicyProvider, IOptions<JwtBearerSettings> jwtBearerSettingsOptions, IOptions<ApiKeySettings> apiKeySettingsOptions)
public AuthenticationOperationFilter(IAuthorizationPolicyProvider authorizationPolicyProvider, IOptions<JwtBearerSettings> jwtBearerSettingsOptions, IOptions<ApiKeySettings> apiKeySettingsOptions, IOptions<Auth0Settings> auth0SettingsOptions)
{
this.authorizationPolicyProvider = authorizationPolicyProvider;
jwtBearerSettings = jwtBearerSettingsOptions.Value;
apiKeySettings = apiKeySettingsOptions.Value;
auth0Settings = auth0SettingsOptions.Value;
}

public void Apply(OpenApiOperation operation, OperationFilterContext context)
Expand All @@ -49,6 +52,9 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context)
CheckAddSecurityRequirement(operation, hasApiKeyHeaderAuthentication ? $"{apiKeySettings.SchemeName} in Header" : null);
CheckAddSecurityRequirement(operation, hasApiKeyQueryAuthentication ? $"{apiKeySettings.SchemeName} in Query String" : null);

var hasAuth0Authentication = !string.IsNullOrWhiteSpace(auth0Settings.Domain);
CheckAddSecurityRequirement(operation, hasAuth0Authentication ? $"{auth0Settings.SchemeName} Bearer" : null);

operation.Responses.TryAdd(StatusCodes.Status401Unauthorized.ToString(), GetResponse(HttpStatusCode.Unauthorized.ToString()));
operation.Responses.TryAdd(StatusCodes.Status403Forbidden.ToString(), GetResponse(HttpStatusCode.Forbidden.ToString()));
}
Expand Down