// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using IdentityServer4; using IdentityServer4.Models; namespace Microsoft.AspNetCore.ApiAuthorization.IdentityServer { /// /// A builder for Clients. /// public class ClientBuilder { private const string NativeAppClientRedirectUri = "urn:ietf:wg:oauth:2.0:oob"; Client _client; private bool _built = false; /// /// Creates a new builder for a single page application that coexists with an authorization server. /// /// The client id for the single page application. /// A . public static ClientBuilder IdentityServerSPA(string clientId) { var client = CreateClient(clientId); return new ClientBuilder(client) .WithApplicationProfile(ApplicationProfiles.IdentityServerSPA) .WithAllowedGrants(GrantTypes.Implicit) .WithAllowedOrigins(Array.Empty()) .AllowAccessTokensViaBrowser(); } /// /// Creates a new builder for an externally registered single page application. /// /// The client id for the single page application. /// A . public static ClientBuilder SPA(string clientId) { var client = CreateClient(clientId); return new ClientBuilder(client) .WithApplicationProfile(ApplicationProfiles.SPA) .WithAllowedGrants(GrantTypes.Implicit) .AllowAccessTokensViaBrowser(); } /// /// Creates a new builder for an externally registered native application. /// /// The client id for the native application. /// A . public static ClientBuilder NativeApp(string clientId) { var client = CreateClient(clientId); return new ClientBuilder(client) .WithApplicationProfile(ApplicationProfiles.NativeApp) .WithAllowedGrants(GrantTypes.Code) .WithRedirectUri(NativeAppClientRedirectUri) .WithLogoutRedirectUri(NativeAppClientRedirectUri) .WithPkce() .WithoutClientSecrets() .WithScopes(IdentityServerConstants.StandardScopes.OfflineAccess); } /// /// Creates a new builder for an externally registered web application. /// /// The client id for the web application. /// A . internal static ClientBuilder WebApplication(string clientId) { var client = CreateClient(clientId); return new ClientBuilder(client) .WithApplicationProfile(ApplicationProfiles.WebApplication) .WithAllowedGrants(GrantTypes.HybridAndClientCredentials) .WithScopes(IdentityServerConstants.StandardScopes.OfflineAccess); } /// /// Initializes a new instance of . /// public ClientBuilder() : this(new Client()) { } /// /// Initializes a new intance of . /// /// A preconfigured client. public ClientBuilder(Client client) { _client = client; } /// /// Updates the client id (and name) of the client. /// /// The new client id. /// The . public ClientBuilder WithClientId(string clientId) { _client.ClientId = clientId; _client.ClientName = clientId; return this; } /// /// Sets the application profile for the client. /// /// The the profile for the application from . /// The . public ClientBuilder WithApplicationProfile(string profile) { _client.Properties.Add(ApplicationProfilesPropertyNames.Profile, profile); return this; } /// /// Adds the to the list of allowed scopes for the client. /// /// The list of scopes. /// The . public ClientBuilder WithScopes(params string[] scopes) { foreach (var scope in scopes) { _client.AllowedScopes.Add(scope); } return this; } /// /// Adds the to the list of valid redirect uris for the client. /// /// The redirect uri to add. /// The . public ClientBuilder WithRedirectUri(string redirectUri) { _client.RedirectUris.Add(redirectUri); return this; } /// /// Adds the to the list of valid logout redirect uris for the client. /// /// The logout uri to add. /// The . public ClientBuilder WithLogoutRedirectUri(string logoutUri) { _client.PostLogoutRedirectUris.Add(logoutUri); return this; } /// /// Adds the to the list of client secrets for the client and configures the client to /// require using the secret when getting tokens from the token endpoint. /// /// The client secret to add. /// The . internal ClientBuilder WithClientSecret(string clientSecret) { _client.ClientSecrets.Add(new Secret(clientSecret)); _client.RequireClientSecret = true; return this; } /// /// Removes any configured client secret from the client and configures it to not require a client secret for getting tokens /// from the token endpoint. /// /// The . public ClientBuilder WithoutClientSecrets() { _client.RequireClientSecret = false; _client.ClientSecrets.Clear(); return this; } /// /// Builds the client. /// /// The built . public Client Build() { if (_built) { throw new InvalidOperationException("Client already built."); } _built = true; return _client; } internal ClientBuilder WithPkce() { _client.RequirePkce = true; _client.AllowPlainTextPkce = false; return this; } internal ClientBuilder FromConfiguration() { _client.Properties[ApplicationProfilesPropertyNames.Source] = ApplicationProfilesPropertyValues.Configuration; return this; } internal ClientBuilder WithAllowedGrants(ICollection grants) { _client.AllowedGrantTypes = grants; return this; } internal ClientBuilder WithAllowedOrigins(params string[] origins) { _client.AllowedCorsOrigins = origins; return this; } internal ClientBuilder AllowAccessTokensViaBrowser() { _client.AllowAccessTokensViaBrowser = true; return this; } private static Client CreateClient(string name) { var client = new Client { ClientId = name, ClientName = name, RequireConsent = false }; return client; } } }