public async Task<string> CreateRefreshTokenAsync(Token accessToken, Client client) { Logger.Debug("Creating refresh token"); int lifetime; if (client.RefreshTokenExpiration == TokenExpiration.Absolute) { Logger.Debug("Setting an absolute lifetime: " + client.AbsoluteRefreshTokenLifetime); lifetime = client.AbsoluteRefreshTokenLifetime; } else { Logger.Debug("Setting a sliding lifetime: " + client.SlidingRefreshTokenLifetime); lifetime = client.SlidingRefreshTokenLifetime; } var refreshToken = new RefreshToken { Handle = Guid.NewGuid().ToString("N"), ClientId = client.ClientId, CreationTime = DateTime.UtcNow, LifeTime = lifetime, AccessToken = accessToken }; await _store.StoreAsync(refreshToken.Handle, refreshToken); return refreshToken.Handle; }
public async Task UpdateConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes) { if (client == null) throw new ArgumentNullException("client"); if (user == null) throw new ArgumentNullException("user"); if (client.AllowRememberConsent) { var subject = user.GetSubjectId(); var clientId = client.ClientId; if (scopes != null && scopes.Any()) { var consent = new Consent { Subject = subject, ClientId = clientId, Scopes = scopes }; await _store.UpdateAsync(consent); } else { await _store.RevokeAsync(subject, clientId); } } }
public DefaultRefreshTokenServiceTests() { originalNowFunc = DateTimeOffsetHelper.UtcNowFunc; DateTimeOffsetHelper.UtcNowFunc = () => UtcNow; roclient_absolute_refresh_expiration_one_time_only = new Client { ClientName = "Resource Owner Client", Enabled = true, ClientId = "roclient_absolute_refresh_expiration_one_time_only", ClientSecrets = new List<ClientSecret> { new ClientSecret("secret".Sha256()) }, Flow = Flows.ResourceOwner, RefreshTokenExpiration = TokenExpiration.Absolute, RefreshTokenUsage = TokenUsage.OneTimeOnly, AbsoluteRefreshTokenLifetime = 200 }; roclient_sliding_refresh_expiration_one_time_only = new Client { ClientName = "Resource Owner Client", Enabled = true, ClientId = "roclient_sliding_refresh_expiration_one_time_only", ClientSecrets = new List<ClientSecret> { new ClientSecret("secret".Sha256()) }, Flow = Flows.ResourceOwner, RefreshTokenExpiration = TokenExpiration.Sliding, RefreshTokenUsage = TokenUsage.OneTimeOnly, AbsoluteRefreshTokenLifetime = 10, SlidingRefreshTokenLifetime = 4 }; roclient_absolute_refresh_expiration_reuse = new Client { ClientName = "Resource Owner Client", Enabled = true, ClientId = "roclient_absolute_refresh_expiration_reuse", ClientSecrets = new List<ClientSecret> { new ClientSecret("secret".Sha256()) }, Flow = Flows.ResourceOwner, RefreshTokenExpiration = TokenExpiration.Absolute, RefreshTokenUsage = TokenUsage.ReUse, AbsoluteRefreshTokenLifetime = 200 }; refreshTokenStore = new InMemoryRefreshTokenStore(); service = new DefaultRefreshTokenService(refreshTokenStore, new DefaultEventService()); }
public async Task CanStoreComplexClient(NpgsqlClientStore store, Fixture fixture, string clientId) { // Given var client = new Client { ClientId = clientId, ClientSecrets = fixture.Create<List<ClientSecret>>(), Flow = Flows.AuthorizationCode, Claims = new List<Claim> { new Claim(fixture.Create("type"), fixture.Create("value"))}, AccessTokenType = AccessTokenType.Jwt, ClientUri = fixture.Create<string>(), ClientName = fixture.Create<string>(), RequireConsent = false, ScopeRestrictions = fixture.Create<List<string>>(), LogoUri = fixture.Create<string>(), Enabled = true, }; // When await store.AddClientAsync(client); // Then var fromDb = await store.FindClientByIdAsync(clientId); fromDb.ShouldNotBe(null); fromDb.ClientId.ShouldBe(clientId); fromDb.ClientSecrets.Count.ShouldBe(client.ClientSecrets.Count); fromDb.Flow.ShouldBe(client.Flow); }
/// <summary> /// Creates the refresh token. /// </summary> /// <param name="accessToken">The access token.</param> /// <param name="client">The client.</param> /// <returns> /// The refresh token handle /// </returns> public async Task<string> CreateRefreshTokenAsync(Token accessToken, Client client) { Logger.Debug("Creating refresh token"); int lifetime; if (client.RefreshTokenExpiration == TokenExpiration.Absolute) { Logger.Debug("Setting an absolute lifetime: " + client.AbsoluteRefreshTokenLifetime); lifetime = client.AbsoluteRefreshTokenLifetime; } else { Logger.Debug("Setting a sliding lifetime: " + client.SlidingRefreshTokenLifetime); lifetime = client.SlidingRefreshTokenLifetime; } var handle = CryptoRandom.CreateUniqueId(); var refreshToken = new RefreshToken { ClientId = client.ClientId, CreationTime = DateTimeOffset.UtcNow, LifeTime = lifetime, AccessToken = accessToken }; await _store.StoreAsync(handle, refreshToken); return handle; }
protected override void ProcessRecord() { var db = new ClientConfigurationDbContext(this.ConnectionString, this.Schema); var client = new Thinktecture.IdentityServer.Core.Models.Client { ClientId = this.ClientId, ClientName = this.ClientName, ClientSecrets = (from s in this.ClientSecrets select new Thinktecture.IdentityServer.Core.Models.ClientSecret(s)).ToList(), Flow = this.Flow, Enabled = this.Enabled, RequireConsent = this.RequireConsent, AllowRememberConsent = this.AllowRememberConsent, ClientUri = this.ClientUri, LogoUri = this.LogoUri, RedirectUris = this.RedirectUris, PostLogoutRedirectUris = this.PostLogoutUris, ScopeRestrictions = this.ScopeRestrictions, IdentityProviderRestrictions = this.IdentityProviderRestrictions, AccessTokenType = this.AccessTokenType, AccessTokenLifetime = this.TokensLifetime, IdentityTokenLifetime = this.TokensLifetime, AuthorizationCodeLifetime = this.TokensLifetime // bad }; db.Clients.Add(client.ToEntity()); db.SaveChanges(); WriteObject(client); }
public async Task<bool> RequiresConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes) { if (client == null) throw new ArgumentNullException("client"); if (user == null) throw new ArgumentNullException("user"); if (!client.RequireConsent) { return false; } // TODO: validate that this is a correct statement if (!client.AllowRememberConsent) { return true; } if (scopes == null || !scopes.Any()) { return false; } var consent = await _store.LoadAsync(user.GetSubjectId(), client.ClientId); if (consent != null && consent.Scopes != null) { var intersect = scopes.Intersect(consent.Scopes); return !(scopes.Count() == intersect.Count()); } return true; }
public virtual async Task<IEnumerable<Claim>> GetIdentityTokenClaimsAsync(ClaimsPrincipal subject, Client client, IEnumerable<Scope> scopes, bool includeAllIdentityClaims, NameValueCollection request) { Logger.Debug("Getting claims for identity token"); List<Claim> outputClaims = new List<Claim>(GetStandardSubjectClaims(subject)); var additionalClaims = new List<string>(); // fetch all identity claims that need to go into the id token foreach (var scope in scopes) { if (scope.IsOpenIdScope) { foreach (var scopeClaim in scope.Claims) { if (includeAllIdentityClaims || scopeClaim.AlwaysIncludeInIdToken) { additionalClaims.Add(scopeClaim.Name); } } } } if (additionalClaims.Count > 0) { var claims = await _users.GetProfileDataAsync(subject.GetSubjectId(), additionalClaims); if (claims != null) { outputClaims.AddRange(claims); } } return outputClaims; }
public DefaultConsentServiceTests() { scopes = new List<string> { "read", "write" }; client = new Client {ClientId = "client", AllowRememberConsent = true, RequireConsent = true}; user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]{new Claim(Constants.ClaimTypes.Subject, "123")}, "password")); store = new InMemoryConsentStore(); subject = new DefaultConsentService(store); }
public override async Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(ClaimsPrincipal subject, Client client, IEnumerable<Scope> scopes, ValidatedRequest request) { var claims = await base.GetAccessTokenClaimsAsync(subject, client, scopes, request); var newClaims = claims.ToList(); newClaims.Add(subject.FindFirst("account_store")); return newClaims; }
public async Task UpdateConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes) { if (client == null) throw new ArgumentNullException("client"); if (user == null) throw new ArgumentNullException("user"); if (client.AllowRememberConsent) { await _store.UpdateConsentAsync(client.ClientId, user.GetSubjectId(), scopes); } }
public async Task<bool> RequiresConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes) { if (client == null) throw new ArgumentNullException("client"); if (user == null) throw new ArgumentNullException("user"); if (!client.RequireConsent) { return false; } return await _store.RequiresConsentAsync(client.ClientId, user.GetSubjectId(), scopes); }
public async Task<ValidationResult> ValidateRequestAsync(NameValueCollection parameters, Client client) { Logger.Info("Starting request validation"); _validatedRequest = new ValidatedTokenRequest(); if (client == null) { throw new ArgumentNullException("client"); } if (parameters == null) { throw new ArgumentNullException("parameters"); } _validatedRequest.Raw = parameters; _validatedRequest.Client = client; _validatedRequest.Settings = _settings; ///////////////////////////////////////////// // check grant type ///////////////////////////////////////////// var grantType = parameters.Get(Constants.TokenRequest.GrantType); if (grantType.IsMissing()) { Logger.Error("Grant type is missing."); return Invalid(Constants.TokenErrors.UnsupportedGrantType); } Logger.InfoFormat("Grant type: {0}", grantType); _validatedRequest.GrantType = grantType; switch (grantType) { case Constants.GrantTypes.AuthorizationCode: return await RunValidationAsync(ValidateAuthorizationCodeRequestAsync, parameters); case Constants.GrantTypes.ClientCredentials: return await RunValidationAsync(ValidateClientCredentialsRequestAsync, parameters); case Constants.GrantTypes.Password: return await RunValidationAsync(ValidateResourceOwnerCredentialRequestAsync, parameters); case Constants.GrantTypes.RefreshToken: return await RunValidationAsync(ValidateRefreshTokenRequestAsync, parameters); } if (parameters.Get(Constants.TokenRequest.Assertion).IsPresent()) { return await RunValidationAsync(ValidateAssertionRequestAsync, parameters); } Logger.ErrorFormat("Unsupported grant_type: {0}", grantType); return Invalid(Constants.TokenErrors.UnsupportedGrantType); }
public async Task<string> UpdateRefreshTokenAsync(RefreshToken refreshToken, Client client) { Logger.Debug("Updating refresh token"); bool needsUpdate = false; string oldHandle = refreshToken.Handle; if (client.RefreshTokenUsage == TokenUsage.OneTimeOnly) { Logger.Debug("Token usage is one-time only. Generating new handle"); // generate new handle refreshToken.Handle = Guid.NewGuid().ToString("N"); needsUpdate = true; } if (client.RefreshTokenExpiration == TokenExpiration.Sliding) { Logger.Debug("Refresh token expiration is sliding - extending lifetime"); // make sure we don't exceed absolute exp // cap it at absolute exp var currentLifetime = refreshToken.CreationTime.GetLifetimeInSeconds(); Logger.Debug("Current lifetime: " + currentLifetime.ToString()); var newLifetime = currentLifetime + client.SlidingRefreshTokenLifetime; Logger.Debug("New lifetime: " + newLifetime.ToString()); if (newLifetime > client.AbsoluteRefreshTokenLifetime) { newLifetime = client.AbsoluteRefreshTokenLifetime; Logger.Debug("New lifetime exceeds absolute lifetime, capping it to " + newLifetime.ToString()); } refreshToken.LifeTime = newLifetime; needsUpdate = true; } if (needsUpdate) { // delete old one await _store.RemoveAsync(oldHandle); // create new one await _store.StoreAsync(refreshToken.Handle, refreshToken); Logger.Debug("Updated refresh token in store"); return refreshToken.Handle; } Logger.Debug("No updates to refresh token done"); return oldHandle; }
/// <summary> /// Returns claims for an identity token /// </summary> /// <param name="subject">The subject</param> /// <param name="client">The client</param> /// <param name="scopes">The requested scopes</param> /// <param name="includeAllIdentityClaims">Specifies if all claims should be included in the token, or if the userinfo endpoint can be used to retrieve them</param> /// <param name="request">The raw request</param> /// <returns> /// Claims for the identity token /// </returns> public virtual async Task<IEnumerable<Claim>> GetIdentityTokenClaimsAsync(ClaimsPrincipal subject, Client client, IEnumerable<Scope> scopes, bool includeAllIdentityClaims, ValidatedRequest request) { Logger.Info("Getting claims for identity token for subject: " + subject.GetSubjectId()); var outputClaims = new List<Claim>(GetStandardSubjectClaims(subject)); outputClaims.AddRange(GetOptionalClaims(subject)); var additionalClaims = new List<string>(); // if a include all claims rule exists, call the user service without a claims filter if (scopes.IncludesAllClaimsForUserRule(ScopeType.Identity)) { Logger.Info("All claims rule found - emitting all claims for user."); var claims = await _users.GetProfileDataAsync(subject); if (claims != null) { outputClaims.AddRange(claims); } return outputClaims; } // fetch all identity claims that need to go into the id token foreach (var scope in scopes) { if (scope.Type == ScopeType.Identity) { foreach (var scopeClaim in scope.Claims) { if (includeAllIdentityClaims || scopeClaim.AlwaysIncludeInIdToken) { additionalClaims.Add(scopeClaim.Name); } } } } if (additionalClaims.Count > 0) { var claims = await _users.GetProfileDataAsync(subject, additionalClaims); if (claims != null) { outputClaims.AddRange(claims); } } return outputClaims; }
public Task UpdateConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes) { if (client.AllowRememberConsent) { var consent = new Consent { ClientId = client.ClientId, Subject = user.GetSubjectId(), Scopes = string.Join(" ", scopes.OrderBy(s => s).ToArray()) }; _consents.Add(consent); } return Task.FromResult(0); }
public Task AddClientAsync(Client client) { Preconditions.IsNotNull(client, nameof(client)); return _conn.ExecuteCommand(_insertQuery, async cmd => { string model = _serializer.Serialize(client); cmd.Parameters.AddWithValue("client", client.ClientId); cmd.Parameters.AddWithValue("model", model); await cmd.ExecuteNonQueryAsync(); return true; }); }
public async Task CanStoreSimpleClient(NpgsqlClientStore store, string clientId) { // Given var client = new Client() { ClientId = clientId }; // When await store.AddClientAsync(client); // Then var fromDb = await store.FindClientByIdAsync(clientId); fromDb.ShouldNotBe(null); fromDb.ClientId.ShouldBe(client.ClientId); }
public static IEnumerable<Client> Get() { var mvcClient = new Client { Enabled = true, ClientName = "GrpTxt", ClientId = "grptxt", Flow = Flows.Hybrid, RedirectUris = new List<Uri> { new Uri("https://b3ncr.comms:44341/"), new Uri("https://b3ncr.comms:44341/#/loggedin?") } }; var apiClient = new Client { Enabled = true, ClientName = "API Client", ClientId = "mvc_service", ClientSecret = "secret", Flow = Flows.ClientCredentials }; var angularClient = new Client { Enabled = true, ClientName = "txtm8", ClientId = "txtm8", Flow = Flows.Hybrid, RedirectUris = new List<Uri> { new Uri("https://b3ncr.comms:44341/#/loggedin?") } }; var implicitClient = new Client { Enabled = true, ClientName = "Implicit Client", ClientId = "Implicit", ClientSecret = "ABC123", Flow = Flows.Implicit, RedirectUris = new List<Uri> { new Uri("https://b3ncr.comms:44341/#/loggedin?") }, RequireConsent = true }; return new List<Client> { mvcClient, implicitClient, apiClient }; }
/// <summary> /// Validates the client secret /// </summary> /// <param name="client">The client.</param> /// <param name="secret">The client secret.</param> /// <returns></returns> public virtual Task<bool> ValidateClientSecretAsync(Client client, string secret) { var secretSha256 = secret.Sha256(); var secretSha512 = secret.Sha512(); foreach (var clientSecret in client.ClientSecrets) { bool isValid = false; byte[] clientSecretBytes; // check if client secret is still valid if (clientSecret.Expiration.HasExpired()) continue; try { clientSecretBytes = Convert.FromBase64String(clientSecret.Value); } catch (FormatException) { // todo: logging throw new InvalidOperationException("Invalid hashing algorithm for client secret."); } if (clientSecretBytes.Length == 32) { isValid = ObfuscatingComparer.IsEqual(clientSecret.Value, secretSha256); } else if (clientSecretBytes.Length == 64) { isValid = ObfuscatingComparer.IsEqual(clientSecret.Value, secretSha512); } else { // todo: logging throw new InvalidOperationException("Invalid hashing algorithm for client secret."); } if (isValid) { return Task.FromResult(true); } } return Task.FromResult(false); }
/// <summary> /// Validates the client secret /// </summary> /// <param name="client">The client.</param> /// <param name="secret">The client secret.</param> /// <returns></returns> public virtual Task<bool> ValidateClientSecretAsync(Client client, string secret) { foreach (var clientSecret in client.ClientSecrets) { // check if client secret is still valid if (clientSecret.Expiration.HasExpired()) continue; // use time constant string comparison var isValid = ObfuscatingComparer.IsEqual(clientSecret.Value, secret); if (isValid) { return Task.FromResult(true); } } return Task.FromResult(false); }
public Task<TokenRevocationRequestValidationResult> ValidateRequestAsync(NameValueCollection parameters, Client client) { if (parameters == null) throw new ArgumentNullException("parameters"); if (client == null) throw new ArgumentNullException("client"); //////////////////////////// // make sure token is present /////////////////////////// var token = parameters.Get("token"); if (token.IsMissing()) { return Task.FromResult(new TokenRevocationRequestValidationResult { IsError = true, Error = Constants.TokenErrors.InvalidRequest }); } var result = new TokenRevocationRequestValidationResult { Token = token }; //////////////////////////// // check token type hint /////////////////////////// var hint = parameters.Get("token_type_hint"); if (hint.IsPresent()) { if (Constants.SupportedTokenTypeHints.Contains(hint)) { result.TokenTypeHint = hint; } else { result.IsError = true; result.Error = Constants.RevocationErrors.UnsupportedTokenType; } } return Task.FromResult(result); }
public virtual Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(ClaimsPrincipal subject, Client client, IEnumerable<Scope> scopes, ICoreSettings settings, IUserService users, NameValueCollection request) { var claims = new List<Claim> { new Claim(Constants.ClaimTypes.ClientId, client.ClientId), }; foreach (var scope in scopes) { claims.Add(new Claim(Constants.ClaimTypes.Scope, scope.Name)); } if (subject != null) { claims.AddRange(GetStandardSubjectClaims(subject)); } return Task.FromResult<IEnumerable<Claim>>(claims); }
public virtual async Task<Token> CreateIdentityTokenAsync(ClaimsPrincipal subject, Client client, IEnumerable<Scope> scopes, bool includeAllIdentityClaims, NameValueCollection request, string accessTokenToHash = null) { Logger.Debug("Creating identity token"); // host provided claims var claims = new List<Claim>(); // if nonce was sent, must be mirrored in id token var nonce = request.Get(Constants.AuthorizeRequest.Nonce); if (nonce.IsPresent()) { claims.Add(new Claim(Constants.ClaimTypes.Nonce, nonce)); } // add iat claim claims.Add(new Claim(Constants.ClaimTypes.IssuedAt, DateTime.UtcNow.ToEpochTime().ToString(), ClaimValueTypes.Integer)); // add at_hash claim if (accessTokenToHash.IsPresent()) { claims.Add(new Claim(Constants.ClaimTypes.AccessTokenHash, HashAccessToken(accessTokenToHash))); } claims.AddRange(await _claimsProvider.GetIdentityTokenClaimsAsync( subject, client, scopes, _settings, includeAllIdentityClaims, _users, request)); var token = new Token(Constants.TokenTypes.IdentityToken) { Audience = client.ClientId, Issuer = _settings.IssuerUri, Lifetime = client.IdentityTokenLifetime, Claims = claims.Distinct(new ClaimComparer()).ToList(), Client = client }; return token; }
protected override void PreInit() { host.Scopes.Add(StandardScopes.OpenId); host.Clients.Add(client = new Client { Enabled = true, ClientId = client_id, ClientSecrets = new List<ClientSecret> { new ClientSecret(client_secret) }, Flow = Flows.AuthorizationCode, RequireConsent = false, RedirectUris = new List<string> { redirect_uri } }); }
public Task<bool> RequiresConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes) { if (!client.RequireConsent) { return Task.FromResult(false); } var orderedScopes = string.Join(" ", scopes.OrderBy(s => s).ToArray()); var query = from c in _consents where c.ClientId == client.ClientId && c.Scopes == orderedScopes && c.Subject == user.GetSubjectId() select c; var hit = query.FirstOrDefault(); return Task.FromResult(hit == null); }
public virtual async Task<Token> CreateAccessTokenAsync(ClaimsPrincipal subject, Client client, IEnumerable<Scope> scopes, NameValueCollection request) { var claims = await _claimsProvider.GetAccessTokenClaimsAsync( subject, client, scopes, _settings, _users, request); var token = new Token(Constants.TokenTypes.AccessToken) { Audience = string.Format(Constants.AccessTokenAudience, _settings.GetIssuerUri()), Issuer = _settings.GetIssuerUri(), Lifetime = client.AccessTokenLifetime, Claims = claims.ToList(), Client = client }; return token; }
public void CanSerializeAndDeserializeAClient() { var client = new Client{ ClientId = "123", Enabled = true, AbsoluteRefreshTokenLifetime = 5, AccessTokenLifetime = 10, AccessTokenType = AccessTokenType.Jwt, AllowRememberConsent = true, RedirectUris = new List<string>{"http://foo.com"} }; var clientStore = new InMemoryClientStore(new Client[]{client}); var converter = new ClientConverter(clientStore); var settings = new JsonSerializerSettings(); settings.Converters.Add(converter); var json = JsonConvert.SerializeObject(client, settings); var result = JsonConvert.DeserializeObject<Client>(json, settings); Assert.AreSame(client, result); }
public static Token CreateAccessToken(Client client, string subjectId, int lifetime, params string[] scopes) { var claims = new List<Claim> { new Claim("client_id", client.ClientId), new Claim("sub", subjectId) }; scopes.ToList().ForEach(s => claims.Add(new Claim("scope", s))); var token = new Token(Constants.TokenTypes.AccessToken) { Audience = "https://idsrv3.com/resources", Issuer = "https://idsrv3.com", Lifetime = lifetime, Claims = claims, Client = client }; return token; }
public bool AreScopesAllowed(Client client, IEnumerable<string> requestedScopes) { if (client.ScopeRestrictions == null || client.ScopeRestrictions.Count == 0) { Logger.Info("All scopes allowed for client"); return true; } else { Logger.Info("Allowed scopes for client client: " + client.ScopeRestrictions.ToSpaceSeparatedString()); foreach (var scope in requestedScopes) { if (!client.ScopeRestrictions.Contains(scope)) { Logger.ErrorFormat("Requested scope not allowed: {0}", scope); return false; } } } return true; }
public bool AreScopesAllowed(Client client, IEnumerable<string> requestedScopes) { if (client.ScopeRestrictions == null || client.ScopeRestrictions.Count == 0) { return true; } foreach (var scope in requestedScopes) { if (!client.ScopeRestrictions.Contains(scope)) { Logger.ErrorFormat("Requested scope not allowed: {0}", scope); return false; } } return true; }
/// <summary> /// Returns claims for an identity token. /// </summary> /// <param name="subject">The subject.</param> /// <param name="client">The client.</param> /// <param name="scopes">The requested scopes.</param> /// <param name="request">The raw request.</param> /// <returns> /// Claims for the access token /// </returns> /// public virtual async Task <IEnumerable <Claim> > GetAccessTokenClaimsAsync(System.Security.Claims.ClaimsPrincipal subject, Thinktecture.IdentityServer.Core.Models.Client client, IEnumerable <Thinktecture.IdentityServer.Core.Models.Scope> scopes, Thinktecture.IdentityServer.Core.Validation.ValidatedRequest request) { // add client_id var outputClaims = new List <Claim> { new Claim(Constants.ClaimTypes.ClientId, client.ClientId), }; // check for client claims if (client.Claims != null && client.Claims.Any()) { if (subject == null || client.AlwaysSendClientClaims) { foreach (var claim in client.Claims) { var claimType = claim.Type; if (client.PrefixClientClaims) { claimType = "client_" + claimType; } outputClaims.Add(new Claim(claimType, claim.Value, claim.ValueType)); } } } // add scopes foreach (var scope in scopes) { outputClaims.Add(new Claim(Constants.ClaimTypes.Scope, scope.Name)); } // a user is involved if (subject != null) { outputClaims.AddRange(GetStandardSubjectClaims(subject)); outputClaims.AddRange(GetOptionalClaims(subject)); // if a include all claims rule exists, call the user service without a claims filter if (scopes.IncludesAllClaimsForUserRule(ScopeType.Resource)) { var claims = await _users.GetProfileDataAsync(subject); if (claims != null) { outputClaims.AddRange(claims); } return(outputClaims); } // fetch all resource claims that need to go into the id token var additionalClaims = new List <string>(); foreach (var scope in scopes) { if (scope.Type == ScopeType.Resource) { if (scope.Claims != null) { foreach (var scopeClaim in scope.Claims) { additionalClaims.Add(scopeClaim.Name); } } } } if (additionalClaims.Count > 0) { var claims = await _users.GetProfileDataAsync(subject, additionalClaims.Distinct()); if (claims != null) { outputClaims.AddRange(claims); } } } outputClaims.AddRange(GetUserClaims(subject)); return(outputClaims); }