diff --git a/src/Gemstone.Security/AccessControl/ResourceAccessType.cs b/src/Gemstone.Security/AccessControl/ResourceAccessType.cs
index baeca622..98880c56 100644
--- a/src/Gemstone.Security/AccessControl/ResourceAccessType.cs
+++ b/src/Gemstone.Security/AccessControl/ResourceAccessType.cs
@@ -94,21 +94,17 @@ public static bool HasAccessTo(this ClaimsPrincipal user, string resourceType, s
{
ThrowIfNotValid(access);
- const string AllowClaim = "Gemstone.ResourceAccess.Allow";
- const string DenyClaim = "Gemstone.ResourceAccess.Deny";
- const string BaseClaim = "Gemstone.ResourceAccess.Default";
-
if (access == ResourceAccessType.None)
return false;
string claimValue = $"{resourceType} {resourceName} {access}";
bool IsDenied() =>
- user.HasClaim(DenyClaim, claimValue);
+ user.HasClaim(GemstoneClaimTypes.DenyClaim, claimValue);
bool IsAllowed() =>
- user.HasClaim(AllowClaim, claimValue) ||
- user.HasClaim(BaseClaim, $"{access}");
+ user.HasClaim(GemstoneClaimTypes.AllowClaim, claimValue) ||
+ user.HasClaim(GemstoneClaimTypes.BaseClaim, $"{access}");
return !IsDenied() && IsAllowed();
}
diff --git a/src/Gemstone.Security/AuthenticationProviders/APIAuthenticationProvider.cs b/src/Gemstone.Security/AuthenticationProviders/APIAuthenticationProvider.cs
new file mode 100644
index 00000000..109a3017
--- /dev/null
+++ b/src/Gemstone.Security/AuthenticationProviders/APIAuthenticationProvider.cs
@@ -0,0 +1,85 @@
+//******************************************************************************************************
+// APIAUthenticationProvider.cs - Gbtc
+//
+// Copyright © 2026, Grid Protection Alliance. All Rights Reserved.
+//
+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
+// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
+// file except in compliance with the License. You may obtain a copy of the License at:
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
+// License for the specific language governing permissions and limitations.
+//
+// Code Modification History:
+// ----------------------------------------------------------------------------------------------------
+// 07/09/2026 - C. Lackner
+// Generated original version of source code.
+//
+//******************************************************************************************************
+
+using System;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+
+namespace Gemstone.Security.AuthenticationProviders;
+
+///
+/// Options for the class.
+///
+public class APIAuthenticationProviderOptions
+{
+ ///
+ /// Function that validates a Token
+ ///
+ public Func? ValidateToken { get; set; }
+
+}
+
+public class APIToken
+{
+ public string Name { get; set; }
+ public DateTime Expiration { get; set; }
+
+ public Claim[] Claims { get; set; }
+}
+
+
+public class APIAuthenticationProvider
+{
+ private readonly RequestDelegate _next;
+ private readonly APIAuthenticationProviderOptions Settings;
+ public APIAuthenticationProvider(RequestDelegate next, APIAuthenticationProviderOptions options)
+ {
+ _next = next;
+ Settings = options;
+ }
+ public async Task InvokeAsync(HttpContext context)
+ {
+ if (context.Request.Headers.TryGetValue("Authorization", out var authHeader))
+ {
+ string bearerToken = authHeader.ToString();
+
+ if (bearerToken.StartsWith("Bearer ", System.StringComparison.OrdinalIgnoreCase))
+ {
+ string token = bearerToken.Substring("Bearer ".Length).Trim();
+ APIToken? resolvedToken = Settings.ValidateToken?.Invoke(token);
+ if (resolvedToken == null || resolvedToken.Expiration < DateTime.UtcNow)
+ {
+ await _next(context);
+ return;
+ }
+ ClaimsIdentity identity = new("APIAuthentication");
+ identity.AddClaim(new(ClaimTypes.Name, resolvedToken.Name));
+ identity.AddClaims(resolvedToken.Claims);
+ context.User = new(identity);
+ await _next(context);
+ }
+ }
+ }
+}
+
diff --git a/src/Gemstone.Security/AuthenticationProviders/IAuthenticationBuilder.cs b/src/Gemstone.Security/AuthenticationProviders/IAuthenticationBuilder.cs
index 669af0dd..a2e2d02c 100644
--- a/src/Gemstone.Security/AuthenticationProviders/IAuthenticationBuilder.cs
+++ b/src/Gemstone.Security/AuthenticationProviders/IAuthenticationBuilder.cs
@@ -96,9 +96,6 @@ public IEnumerable GetProviderIdentities()
public IEnumerable GetAssignedClaims(string providerIdentity, ClaimsPrincipal principal)
{
- const string ProviderIdentityClaim = "Gemstone.ProviderIdentity";
- const string UserIdentityClaim = "Gemstone.UserIdentity";
-
IAuthenticationProvider? provider = ProviderLookup(providerIdentity);
if (provider is null)
@@ -106,11 +103,13 @@ public IEnumerable GetAssignedClaims(string providerIdentity, ClaimsPrinc
string userIdentity = provider.GetIdentity(principal);
- IEnumerable providerClaims = Setup
- .GetProviderClaims(providerIdentity)
- .Join(principal.Claims, ToKey, ToKey, (providerClaim, _) => providerClaim.Assigned)
- .Prepend(new(UserIdentityClaim, userIdentity))
- .Prepend(new(ProviderIdentityClaim, providerIdentity));
+ IEnumerable principalClaims = principal.Claims
+ .Append(new(GemstoneClaimTypes.AllUsers,string.Empty));
+
+ IEnumerable providerClaims = Setup.GetProviderClaims(providerIdentity)
+ .Join(principalClaims, ToKey, ToKey, (providerClaim, _) => providerClaim.Assigned)
+ .Prepend(new(GemstoneClaimTypes.UserIdentity, userIdentity))
+ .Prepend(new(GemstoneClaimTypes.ProviderIdentity, providerIdentity));
return providerClaims;
}
diff --git a/src/Gemstone.Security/AuthenticationProviders/OAuthAuthenticationProvider.cs b/src/Gemstone.Security/AuthenticationProviders/OAuthAuthenticationProvider.cs
index b5266466..afa14dda 100644
--- a/src/Gemstone.Security/AuthenticationProviders/OAuthAuthenticationProvider.cs
+++ b/src/Gemstone.Security/AuthenticationProviders/OAuthAuthenticationProvider.cs
@@ -127,7 +127,7 @@ public string GetIdentity(ClaimsPrincipal principal)
.Claims
.Select(claim => claim.Type)
.Distinct()
- .Select(type => new ClaimType(type)).Prepend(new ClaimType("Gemstone.AllUsers")).ToArray();
+ .Select(type => new ClaimType(type)).ToArray();
string? identity = principal
.FindFirst(Options.UserIdClaim ?? "sub")?
@@ -158,7 +158,7 @@ private static ClaimType[] ClaimTypes
{
get;
set;
- } = [new ClaimType("Gemstone.AllUsers")];
+ } = [new ClaimType(GemstoneClaimTypes.AllUsers), new (GemstoneClaimTypes.UserIdentity)];
// Static Methods
diff --git a/src/Gemstone.Security/GemstoneClaimTypes.cs b/src/Gemstone.Security/GemstoneClaimTypes.cs
new file mode 100644
index 00000000..06a18e71
--- /dev/null
+++ b/src/Gemstone.Security/GemstoneClaimTypes.cs
@@ -0,0 +1,63 @@
+//******************************************************************************************************
+// GemstoneClaimTypes.cs - Gbtc
+//
+// Copyright © 2026, Grid Protection Alliance. All Rights Reserved.
+//
+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
+// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
+// file except in compliance with the License. You may obtain a copy of the License at:
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
+// License for the specific language governing permissions and limitations.
+//
+// Code Modification History:
+// ----------------------------------------------------------------------------------------------------
+// 10/16/2019 - J. Ritchie Carroll
+// Generated original version of source code.
+//
+//******************************************************************************************************
+
+using System.Runtime.CompilerServices;
+
+namespace Gemstone.Security
+{
+ ///
+ /// The Claim Types used bu the namespace
+ ///
+ public static class GemstoneClaimTypes
+ {
+ ///
+ /// Holds the unique identifier for the User.
+ ///
+ public const string UserIdentity = "Gemstone.UserIdentity";
+ ///
+ /// Holds the unique identifier for the Authentication Provider.
+ ///
+ public const string ProviderIdentity = "Gemstone.ProviderIdentity";
+
+ ///
+ /// Is used in Matrching Claims to match any user, regardless of claims they have
+ ///
+ public const string AllUsers = "Gemstone.AllUsers";
+
+ ///
+ /// Allows a user to access a resource.
+ ///
+ public const string AllowClaim = "Gemstone.ResourceAccess.Allow";
+
+ ///
+ /// Denies a user access to a resource.
+ ///
+ public const string DenyClaim = "Gemstone.ResourceAccess.Deny";
+
+ ///
+ /// Allows access to the value as the default access level.
+ ///
+ public const string BaseClaim = "Gemstone.ResourceAccess.Default";
+
+ }
+}