Configures OIDC with explicit endpoints
All checks were successful
Build, Push and Run Container / build (push) Successful in 24s
All checks were successful
Build, Push and Run Container / build (push) Successful in 24s
Configures the OpenID Connect (OIDC) authentication flow by explicitly setting the authorization, token, JWKS, end session, and user info endpoints. This change removes the custom OIDC configuration manager and directly sets the configuration within the OIDC options. This approach simplifies the configuration and ensures that the application uses the correct endpoints for authentication and authorization with the third-party provider.
This commit is contained in:
@@ -11,13 +11,12 @@ using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
|
||||
public sealed class TeslaOIDCConfigurationManager : IConfigurationManager<OpenIdConnectConfiguration>
|
||||
{
|
||||
private readonly Func<string, string> urlOverride;
|
||||
private readonly IConfigurationManager<OpenIdConnectConfiguration> _inner;
|
||||
private readonly string _tokenEndpointOverride;
|
||||
|
||||
// No HttpClient/ServiceProvider needed — uses default retriever internally
|
||||
public TeslaOIDCConfigurationManager(string metadataAddress, string tokenEndpointOverride)
|
||||
public TeslaOIDCConfigurationManager(string metadataAddress, Func<string, string> urlOverride)
|
||||
{
|
||||
_tokenEndpointOverride = tokenEndpointOverride;
|
||||
this.urlOverride = urlOverride;
|
||||
_inner = new ConfigurationManager<OpenIdConnectConfiguration>(
|
||||
metadataAddress,
|
||||
new OpenIdConnectConfigurationRetriever());
|
||||
@@ -25,51 +24,10 @@ public sealed class TeslaOIDCConfigurationManager : IConfigurationManager<OpenId
|
||||
|
||||
public async Task<OpenIdConnectConfiguration> GetConfigurationAsync(CancellationToken cancel)
|
||||
{
|
||||
var cfg = await _inner.GetConfigurationAsync(cancel).ConfigureAwait(false);
|
||||
cfg.TokenEndpoint = _tokenEndpointOverride; // <-- required by Tesla
|
||||
return cfg;
|
||||
OpenIdConnectConfiguration? configuration = await _inner.GetConfigurationAsync(cancel);
|
||||
configuration.TokenEndpoint = urlOverride(configuration.TokenEndpoint);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public void RequestRefresh() => _inner.RequestRefresh();
|
||||
|
||||
public sealed class SigningKeyResolver
|
||||
{
|
||||
private readonly HttpClient backChannel;
|
||||
private readonly TimeSpan cacheDuration;
|
||||
private readonly ConcurrentDictionary<string, (DateTimeOffset exp, SecurityKey[] keys)> cache;
|
||||
|
||||
public SigningKeyResolver(HttpClient backChannel, TimeSpan cacheDuration)
|
||||
{
|
||||
this.backChannel = backChannel;
|
||||
this.cacheDuration = cacheDuration;
|
||||
this.cache = new ConcurrentDictionary<string,(DateTimeOffset exp, SecurityKey[] keys)>();
|
||||
}
|
||||
|
||||
public IEnumerable<SecurityKey> Resolve(string token, SecurityToken securityToken, string kid, TokenValidationParameters validationParameters)
|
||||
{
|
||||
JwtSecurityToken jwt = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(token);
|
||||
string? issuer = jwt.Issuer?.TrimEnd('/');
|
||||
|
||||
// Issuer is empty
|
||||
if (string.IsNullOrEmpty(issuer))
|
||||
return Array.Empty<SecurityKey>();
|
||||
|
||||
// Serve from cache if fresh
|
||||
if (cache.TryGetValue(issuer, out var entry) && entry.exp > DateTimeOffset.UtcNow)
|
||||
return entry.keys;
|
||||
|
||||
// Fetch JWKS from the same issuer (sync-over-async kept local to this callback)
|
||||
string jwksUrl = $"{issuer}/certs";
|
||||
string json = backChannel.GetStringAsync(jwksUrl).GetAwaiter().GetResult();
|
||||
|
||||
// Get result
|
||||
JsonWebKeySet jwks = new JsonWebKeySet(json);
|
||||
SecurityKey[] keys = jwks.Keys.Select(k => (SecurityKey)k).ToArray();
|
||||
|
||||
// Cache
|
||||
cache[issuer] = (DateTimeOffset.UtcNow.Add(this.cacheDuration), keys);
|
||||
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user