From 1e20544093c5e6dac170979173e95487f41c3c86 Mon Sep 17 00:00:00 2001 From: pfvatterott Date: Thu, 26 Jun 2025 09:09:39 -0600 Subject: [PATCH 1/2] Removed OAuth --- PropelAuth.Tests/PropelAuthOptionsTests.cs | 41 ---- PropelAuth/PropelAuth.csproj | 5 +- PropelAuth/PropelAuthExtensions.cs | 216 --------------------- PropelAuth/PropelAuthOptions.cs | 102 ---------- PropelAuth/User.cs | 28 ++- 5 files changed, 28 insertions(+), 364 deletions(-) delete mode 100644 PropelAuth.Tests/PropelAuthOptionsTests.cs delete mode 100644 PropelAuth/PropelAuthExtensions.cs delete mode 100644 PropelAuth/PropelAuthOptions.cs diff --git a/PropelAuth.Tests/PropelAuthOptionsTests.cs b/PropelAuth.Tests/PropelAuthOptionsTests.cs deleted file mode 100644 index 7bac925..0000000 --- a/PropelAuth.Tests/PropelAuthOptionsTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using PropelAuth.Models; -using Xunit; - -namespace PropelAuth.Tests -{ - public class PropelAuthOptionsTests - { - [Fact] - public void Constructor_ShouldInitializeProperties() - { - // Arrange - string authUrl = "https://auth.example.com"; - string apiKey = "api_12345"; - string publicKey = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."; - - // Act - var options = new PropelAuthOptions(authUrl, apiKey, publicKey); - - // Assert - Assert.Equal(authUrl, options.AuthUrl); - Assert.Equal(apiKey, options.ApiKey); - Assert.Equal(publicKey, options.PublicKey); - } - - [Fact] - public void Constructor_ShouldAcceptNullPublicKey() - { - // Arrange - string authUrl = "https://auth.example.com"; - string apiKey = "api_12345"; - - // Act - var options = new PropelAuthOptions(authUrl, apiKey); - - // Assert - Assert.Equal(authUrl, options.AuthUrl); - Assert.Equal(apiKey, options.ApiKey); - Assert.Null(options.PublicKey); - } - } -} \ No newline at end of file diff --git a/PropelAuth/PropelAuth.csproj b/PropelAuth/PropelAuth.csproj index 1972bf5..5be5ded 100644 --- a/PropelAuth/PropelAuth.csproj +++ b/PropelAuth/PropelAuth.csproj @@ -7,7 +7,7 @@ PropelAuth - 0.1.0 + 0.1.1 PropelAuth PropelAuth Official .NET SDK for PropelAuth authentication and authorization @@ -33,10 +33,7 @@ - - - diff --git a/PropelAuth/PropelAuthExtensions.cs b/PropelAuth/PropelAuthExtensions.cs deleted file mode 100644 index 1850fb4..0000000 --- a/PropelAuth/PropelAuthExtensions.cs +++ /dev/null @@ -1,216 +0,0 @@ -using System.IdentityModel.Tokens.Jwt; -using System.Security.Cryptography; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Authentication.OAuth; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.IdentityModel.Tokens; -using Newtonsoft.Json.Linq; -using PropelAuth.Models; - -namespace PropelAuth -{ - /// - /// Extension methods for configuring PropelAuth authentication in an ASP.NET Core application. - /// - public static class PropelAuthExtensions - { - /// - /// Adds PropelAuth authentication to the service collection. - /// - /// The service collection to add authentication to. - /// The PropelAuth configuration options. - /// The service collection for chaining. - /// Thrown when the API key is invalid or the verifier key cannot be retrieved. - public static async Task AddPropelAuthAsync(this IServiceCollection services, - PropelAuthOptions options) - { - // Get the public key either from options or from the PropelAuth API - string publicKey = await GetPublicKeyAsync(options); - - // Configure RSA with the public key - var rsa = ConfigureRsaWithPublicKey(publicKey); - - // Add authentication with JWT bearer - ConfigureAuthentication(services, options, rsa); - - return services; - } - - #region Private Helper Methods - - /// - /// Gets the public key either from options or from the PropelAuth API. - /// - /// The PropelAuth configuration options. - /// The public key in PEM format. - private static async Task GetPublicKeyAsync(PropelAuthOptions options) - { - if (!string.IsNullOrEmpty(options.PublicKey)) - { - return options.PublicKey; - } - - return await GetVerifierKeyPemAsync(options.AuthUrl, options.ApiKey); - } - - /// - /// Configures RSA with the provided public key. - /// - /// The public key in PEM format. - /// An initialized RSA instance. - private static RSA ConfigureRsaWithPublicKey(string publicKey) - { - var rsa = RSA.Create(); - rsa.ImportFromPem(publicKey); - return rsa; - } - - /// - /// Configures authentication with JWT bearer. - /// - /// The service collection to add authentication to. - /// The PropelAuth configuration options. - /// The RSA instance configured with the public key. - private static void ConfigureAuthentication(IServiceCollection services, PropelAuthOptions options, RSA rsa) - { - var authBuilder = services.AddAuthentication(authOptions => - { - if (options.OAuthOptions is {AllowBearerTokenAuth: true}) - { - authOptions.DefaultAuthenticateScheme = "OAuthOrBearer"; - authOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; - authOptions.DefaultChallengeScheme = "OAuthOrBearer"; - } - else if (options.OAuthOptions != null) - { - authOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; - authOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; - authOptions.DefaultChallengeScheme = "OAuth"; - } - else - { - authOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - authOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - } - }); - - if (options.OAuthOptions is {AllowBearerTokenAuth: true}) - { - authBuilder.AddPolicyScheme("OAuthOrBearer", "OAuth or Bearer", policyOptions => - { - policyOptions.ForwardDefaultSelector = context => - { - if (context.Request.Headers.ContainsKey("Authorization")) - { - return JwtBearerDefaults.AuthenticationScheme; - } - - return "OAuth"; - }; - }); - } - - - if (options.OAuthOptions == null || options.OAuthOptions.AllowBearerTokenAuth == true) - { - authBuilder.AddJwtBearer(jwtOptions => - { - jwtOptions.TokenValidationParameters = new TokenValidationParameters - { - ValidateAudience = false, - ValidAlgorithms = new List() {"RS256"}, - ValidIssuer = options.AuthUrl, - IssuerSigningKey = new RsaSecurityKey(rsa), - ValidateLifetime = true, - }; - }); - } - - if (options.OAuthOptions != null) - { - authBuilder - .AddCookie(cookieOptions => - { - cookieOptions.Cookie.SameSite = SameSiteMode.Lax; - cookieOptions.Cookie.HttpOnly = true; - cookieOptions.Cookie.SecurePolicy = CookieSecurePolicy.Always; - cookieOptions.SlidingExpiration = true; - }) - .AddOAuth("OAuth", configOptions => - { - configOptions.AuthorizationEndpoint = $"{options.AuthUrl}/propelauth/oauth/authorize"; - configOptions.TokenEndpoint = $"{options.AuthUrl}/propelauth/oauth/token"; - configOptions.UserInformationEndpoint = $"{options.AuthUrl}/propelauth/oauth/userinfo"; - configOptions.ClientId = options.OAuthOptions.ClientId; - configOptions.ClientSecret = options.OAuthOptions.ClientSecret; - configOptions.CallbackPath = options.OAuthOptions.CallbackPath; - configOptions.SaveTokens = true; - configOptions.Events = new OAuthEvents - { - OnCreatingTicket = context => - { - var token = context.AccessToken; - var handler = new JwtSecurityTokenHandler(); - var jwt = handler.ReadJwtToken(token); - foreach (var claim in jwt.Claims) - { - context.Identity?.AddClaim(claim); - } - - return Task.CompletedTask; - } - }; - }); - } - - services.AddAuthorization(); - } - - /// - /// Gets the verifier key in PEM format from the PropelAuth API. - /// - /// The PropelAuth issuer URL. - /// The PropelAuth API key. - /// The verifier key in PEM format. - /// Thrown when the API key is invalid or the verifier key cannot be retrieved. - private static async Task GetVerifierKeyPemAsync(string issuer, string apiKey) - { - using (var client = new HttpClient()) - { - client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}"); - var response = await client.GetAsync($"{issuer}/api/v1/token_verification_metadata"); - - if (response.IsSuccessStatusCode) - { - return await ParseVerifierKeyFromResponse(response); - } - - throw new Exception("Error in initializing library, this is likely due to an incorrect API Key"); - } - } - - /// - /// Parses the verifier key from the API response. - /// - /// The HTTP response from the PropelAuth API. - /// The verifier key in PEM format. - /// Thrown when the verifier key is missing in the response. - private static async Task ParseVerifierKeyFromResponse(HttpResponseMessage response) - { - var content = await response.Content.ReadAsStringAsync(); - var json = JObject.Parse(content); - var verifierKeyPem = json["verifier_key_pem"]?.ToString(); - - if (verifierKeyPem == null) - { - throw new Exception("verifier_key_pem is missing in the response"); - } - - return verifierKeyPem; - } - - #endregion - } -} \ No newline at end of file diff --git a/PropelAuth/PropelAuthOptions.cs b/PropelAuth/PropelAuthOptions.cs deleted file mode 100644 index 9edc63b..0000000 --- a/PropelAuth/PropelAuthOptions.cs +++ /dev/null @@ -1,102 +0,0 @@ -namespace PropelAuth.Models -{ - /// - /// Configuration options for PropelAuth authentication service. - /// - public class PropelAuthOptions - { - #region Properties - - /// - /// Gets the public key used for token verification. - /// - /// - /// This key is optional, if unspecified, we will fetch the public key from the authentication service. - /// - public string? PublicKey { get; } - - /// - /// Gets the base URL for the PropelAuth authentication service. - /// - public string AuthUrl { get; } - - /// - /// Gets the API key used for authenticating requests to PropelAuth. - /// - public string ApiKey { get; } - - /// - /// If you are using PropelAuth's OAuth feature, you can specify the OAuth options here. - /// - public OAuthOptions? OAuthOptions { get; } - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - /// The base URL for the PropelAuth authentication service. - /// The API key used for authenticating requests to PropelAuth. - /// Optional. The public key used for token verification. - /// Optional. The OAuth options if you are using PropelAuth's OAuth feature. - public PropelAuthOptions(string authUrl, string apiKey, string? publicKey = null, - OAuthOptions? oAuthOptions = null) - { - AuthUrl = authUrl; - ApiKey = apiKey; - PublicKey = publicKey; - OAuthOptions = oAuthOptions; - } - - #endregion - } - - public class OAuthOptions - { - #region Properties - - /// - /// The client ID for the OAuth application. - /// - public string ClientId { get; } - - /// - /// The client secret for the OAuth application. - /// - public string ClientSecret { get; } - - /// - /// The callback path for the OAuth application. Defaults to "/callback" - /// - public string? CallbackPath { get; } - - /// - /// Whether to allow requests via an authorization header `Bearer {TOKEN}`. Default false. - /// - public bool? AllowBearerTokenAuth { get; } - - #endregion - - #region Constructor - - /// - /// Initializes a new instance of the class. - /// - /// The client ID for the OAuth application. - /// The client secret for the OAuth application. - /// Optional. The callback path for the OAuth application. Defaults to "/callback" - /// Optional. Whether to allow requests via an authorization header `Bearer {TOKEN}`. Default false. - public OAuthOptions(string clientId, string clientSecret, string? callbackPath = "/callback", bool? allowBearerTokenAuth = false) - { - ClientId = clientId; - ClientSecret = clientSecret; - CallbackPath = callbackPath; - AllowBearerTokenAuth = allowBearerTokenAuth; - } - - #endregion - - } -} \ No newline at end of file diff --git a/PropelAuth/User.cs b/PropelAuth/User.cs index 3932b03..41934c2 100644 --- a/PropelAuth/User.cs +++ b/PropelAuth/User.cs @@ -10,15 +10,41 @@ public class User { #region Properties - // Public properties + /// + /// The unique identifier for the user. + /// public string UserId { get; } + /// + /// The email address of the user. + /// public string Email { get; } + /// + /// The user's first name + /// public string? FirstName { get; } + /// + /// The user's last name + /// public string? LastName { get; } + /// + /// The user's username + /// public string? Username { get; } + /// + /// The user's legacy user ID. This is only set if you migrated from an external source + /// public string? LegacyUserId { get; } + /// + /// The method the user used to log in. Returns an instance of that describes the login method. + /// public LoginMethod LoginMethod { get; } + /// + /// If the user is being impersonated, this is the ID of the impersonator. + /// public string? ImpersonatorUserId { get; } + /// + /// Additional properties set on the user. + /// public Dictionary? Properties { get; } // Private properties From b7de5d6955adfaa3304b3719ce423b69a0838af2 Mon Sep 17 00:00:00 2001 From: pfvatterott Date: Fri, 27 Jun 2025 12:39:58 -0600 Subject: [PATCH 2/2] Update version --- PropelAuth/PropelAuth.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PropelAuth/PropelAuth.csproj b/PropelAuth/PropelAuth.csproj index 5be5ded..bd70dda 100644 --- a/PropelAuth/PropelAuth.csproj +++ b/PropelAuth/PropelAuth.csproj @@ -7,7 +7,7 @@ PropelAuth - 0.1.1 + 0.2.0 PropelAuth PropelAuth Official .NET SDK for PropelAuth authentication and authorization