How do I avoid using a client secret or certificate for Blazor Server when using MSAL? - authentication

When using Blazor Server and the MSAL library you must provide either a client secret or a client certificate. Here is what a Blazor Server project uses to setup the authentication out of the box.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
However in the Blazor WASM (Or Blazor Client) project they set things up this way
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
});
Obviously this method doesn't require a Client Secret for security reasons. The AddMsalAuthentication() method that it uses is only found in the WebAssembly MSAL library.
We don't use a key vault as our company doesn't want to pay for one at this time. So we have to manually update all the client secrets every 24 months. To avoid this we want to try to implement a public client flow in our Blazor Server apps. We already have a bunch of them so we don't want to have to move them to WebAssembly.
I did try to implement using a public client builder manually but the .AddMicrosoftIdentityWebApp() portion would still require a client secret to allow the first login.
In Blazor Server is there a way to implement the same behavior as the WebAssembly authentication, in other words, can we avoid using Client Secrets and Certificates?

I would recommend to do as the following to be able to retrieve access token without client secret.
Statup class:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(o => {
o.UsePkce = true;
o.ClientId = "clientId";
o.TenantId = "tenantId";
o.Domain = "domain.onmicrosoft.com";
o.Instance = "https://login.microsoftonline.com";
o.CallbackPath = "/signin-oidc";
o.Scope.Add("scopeApi1");
o.Scope.Add("offline_access");
o.ResponseType = "code";
var defaultBackChannel = new HttpClient(); defaultBackChannel.DefaultRequestHeaders.Add("Origin", "thisismyapp");
o.Backchannel = defaultBackChannel;
});
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.SaveTokens = true;
options.Events.OnTokenValidated = async context =>
{
// Here you will be able to see the accesstoken.
var accessToken = context.TokenEndpointResponse.AccessToken;
var refreshToken = context.TokenEndpointResponse.RefreshToken;
};
});
In your case change the "service" to "builder.Services".
Then in the _Host.cshtml
var accessToken = await HttpContext.GetTokenAsync("access_token");
var refreshToken = await HttpContext.GetTokenAsync("refresh_token");
<component type="typeof(App)" param-AccessToken="#accessToken" param-RefreshToken="#refreshToken" render-mode="Server" />
In App.razor:
[Parameter]
public string AccessToken { get; set; }
[Parameter]
public string RefreshToken { get; set; }
From here you will be able to do what ever you want with the accesstoken..
Some issue i have been facing with this, is how to get a new accesstoken with the refreshtoken without client secret. If you figure it out, let me know.

Related

Migrating to Openiddict 4.0.0 breaks HotChocolate GraphQL authorization for client credentials flow if token encryption is enabled

I've an ASP.NET Core project which hosts both an identity server using Openiddict and a resource server using HotChocolate GraphQL package.
Client-credentials flow is enabled in the system. The token is encrypted using RSA algorithm.
Till now, I had Openiddict v3.1.1 and everything used to work flawlessly. Recently, I've migrated to Openiddict v4.0.0. Following this, the authorization has stopped working. If I disable token encyption then authorization works as expected. On enabling token encyption, I saw in debugging, that claims are not being passed at all. I cannot switch off token encyption, as it is a business and security requirement. The Openiddict migration guidelines doesn't mention anything about any change related to encryption keys. I need help to make this work as Openiddict v3.1.1 is no longer supported for bug fixes.
The OpenIddict setup in ASP.NET Core pipeline:
public static void AddOpenIddict(this IServiceCollection services, IConfiguration configuration)
{
var openIddictOptions = configuration.GetSection("OpenIddict").Get<OpenIddictOptions>();
var encryptionKeyData = openIddictOptions.EncryptionKey.RSA;
var signingKeyData = openIddictOptions.SigningKey.RSA;
var encryptionKey = RSA.Create();
var signingKey = RSA.Create();
encryptionKey.ImportFromEncryptedPem(encryptionKeyData.ToCharArray(),
openIddictOptions.EncryptionKey.Passphrase.ToCharArray());
signingKey.ImportFromEncryptedPem(signingKeyData.ToCharArray(),
openIddictOptions.SigningKey.Passphrase.ToCharArray());
encryptionKey.ImportFromEncryptedPem(encryptionKeyData.ToCharArray(),
openIddictOptions.EncryptionKey.Passphrase.ToCharArray());
signingKey.ImportFromEncryptedPem(signingKeyData.ToCharArray(),
openIddictOptions.SigningKey.Passphrase.ToCharArray());
var sk = new RsaSecurityKey(signingKey);
var ek = new RsaSecurityKey(encryptionKey);
services.AddOpenIddict()
.AddCore(options =>
{
options.UseEntityFrameworkCore()
.UseDbContext<AuthDbContext>()
.ReplaceDefaultEntities<Guid>();
})
.AddServer(options =>
{
// https://documentation.openiddict.com/guides/migration/30-to-40.html#update-your-endpoint-uris
options.SetCryptographyEndpointUris("oauth2/.well-known/jwks");
options.SetConfigurationEndpointUris("oauth2/.well-known/openid-configuration");
options.SetTokenEndpointUris("oauth2/connect/token");
options.AllowClientCredentialsFlow();
options.SetUserinfoEndpointUris("oauth2/connect/userinfo");
options.SetIntrospectionEndpointUris("oauth2/connect/introspection");
options.AddSigningKey(sk);
options.AddEncryptionKey(ek);
//options.DisableAccessTokenEncryption(); // If this line is not commented, things work as expected
options.UseAspNetCore(o =>
{
// NOTE: disabled because by default OpenIddict accepts request from HTTPS endpoints only
o.DisableTransportSecurityRequirement();
o.EnableTokenEndpointPassthrough();
});
})
.AddValidation(options =>
{
options.UseLocalServer();
options.UseAspNetCore();
});
}
Authorization controller token get action:
[HttpPost("~/oauth2/connect/token")]
[Produces("application/json")]
public async Task<IActionResult> Exchange()
{
var request = HttpContext.GetOpenIddictServerRequest();
if (request.IsClientCredentialsGrantType())
{
// Note: the client credentials are automatically validated by OpenIddict:
// if client_id or client_secret are invalid, this action won't be invoked.
var application = await _applicationManager.FindByClientIdAsync(request.ClientId);
if (application == null)
{
throw new InvalidOperationException("The application details cannot be found in the database.");
}
// Create a new ClaimsIdentity containing the claims that
// will be used to create an id_token, a token or a code.
var identity = new ClaimsIdentity(
authenticationType: TokenValidationParameters.DefaultAuthenticationType,
nameType: OpenIddictConstants.Claims.Name,
roleType: OpenIddictConstants.Claims.Role);
var clientId = await _applicationManager.GetClientIdAsync(application);
var organizationId = await _applicationManager.GetDisplayNameAsync(application);
// https://documentation.openiddict.com/guides/migration/30-to-40.html#remove-calls-to-addclaims-that-specify-a-list-of-destinations
identity.SetClaim(type: OpenIddictConstants.Claims.Subject, value: organizationId)
.SetClaim(type: OpenIddictConstants.Claims.ClientId, value: clientId)
.SetClaim(type: "organization_id", value: organizationId);
identity.SetDestinations(static claim => claim.Type switch
{
_ => new[] { OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken }
});
return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
throw new NotImplementedException("The specified grant type is not implemented.");
}
Resource controller (where Authorization is not working):
public class Query
{
private readonly IMapper _mapper;
public Query(IMapper mapper)
{
_mapper = mapper;
}
[HotChocolate.AspNetCore.Authorization.Authorize]
public async Task<Organization> GetMe(ClaimsPrincipal claimsPrincipal,
[Service] IDbContextFactory<DbContext> dbContextFactory,
CancellationToken ct)
{
var organizationId = Ulid.Parse(claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier));
... // further code removed for brevity
}
}
}
GraphQL setup in ASP.NET Core pipeline:
public static void AddGraphQL(this IServiceCollection services, IWebHostEnvironment webHostEnvironment)
{
services.AddGraphQLServer()
.AddAuthorization()
.AddQueryType<Query>()
}
Packages with versions:
OpenIddict (4.0.0)
OpenIddict.AspNetCore (4.0.0)
OpenIddict.EntityFrameworkCore (4.0.0)
HotChocolate.AspNetCore (12.13.2)
HotChocolate.AspNetCore.Authorization (12.13.2)
HotChocolate.Diagnostics (12.13.2)
I think you can look at the logs to figure out exactly what's going on:
Logging in .NET Core and ASP.NET Core.
Not sure if the Openiddict 4.0 release changed encryption key related configuration, but if you can't get encryption keys to work perhaps you can remove the OpenIddict validation part and configure the JWT bearer handler instance to use the appropriate encryption key , a configuration similar to this.
Of course, you can also open an issue in GitHub to ask #Kévin Chalet.

Can I access my ID Token from an AuthenticationStateProvider in my Blazor client?

I'm trying to access the ID Token provided by Azure AD. I really need to get access to the signature and all of the claims.
I can easily access the AuthenticationStateProvider and then get the User from that. The User property has all of the claims in it, but that seems to be all. I cannot figure out how to get access to the rest of the ID Token.
Here is the code I'm using in the code behind on my blazor page:
[Inject]
AuthenticationStateProvider authenticationState { get; set; }
public async Task<string> GetIDTokenAsync()
{
var authState = await authenticationState.GetAuthenticationStateAsync();
return string.Join(", ", authState.User.Claims.ToList());
}
I'm just returning the list as a string to see what data I'm getting.
Additionally, my bootstrap looks like this:
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
});
await builder.Build().RunAsync();
}
}
After I open the website I log in using the RemoteAuthenticatorView component. I need to access the ID Token after logging in. Also I just want to clarify that I am not looking for the access token. I do not ask for any scopes, and therefore there is no access token. My goal here is to get the ID Token and pass it to my API where the API can verify the ID Token and then issue it's own access token.

User is authenticated after OpenId Connect (AAD) but Unable to find access token

I am trying to find the access token from AAD after user is authenticated from OpenId Connect. It is a web application integrated with AAD OpenId Connect. I need to get the access token to call another API that uses the same AAD. Here's what I've tried:
Clone this sample code.
In Startup.cs file, add the following block of code:
public void ConfigureServices(IServiceCollection services) {
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor();
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddAzureAd(options => Configuration.Bind("AzureAd", options))
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "http://localhost:5000";
options.ClientId = "<<client-id>>";
options.SignInScheme = "cookie";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.RequireHttpsMetadata = false;
})
.AddCookie();
services.AddMvc();}
In HomeController class, I added a private variable called httpContextAccessor and also set it in the constructor.
private IHttpContextAccessor _httpContextAccessor;
public HomeController(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
In the HomeController class, I added some code to access the access token.
public IActionResult Index()
{
if (User.Identity.IsAuthenticated)
{
var attempt1 = Request.Headers["Authorization"];
var attempt2 = HttpContext.GetTokenAsync("access_token");
var attempt3 = _httpContextAccessor.HttpContext.GetTokenAsync("access_token");
var attempt4 = _httpContextAccessor.HttpContext.Request.Headers["Authorziation"];
}
return View();
}
But all of them return either empty or null. Did I miss anything?
I've looked at this following posts for reference:
How to refresh access token
How to get access token from HttpContext in .Net core 2.0
You need to set SaveTokens to true in OpenID Connect configuration:
Clone that code sample
Keep the Startup.cs , you don't need to add .AddOpenIdConnect part , AddAzureAd extension method would help add Azure Active Directory Authentication to your application.
Modify the AzureAdAuthenticationBuilderExtensions.cs in Extensions folder :
public void Configure(string name, OpenIdConnectOptions options)
{
options.ClientId = _azureOptions.ClientId;
options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
options.UseTokenLifetime = true;
options.CallbackPath = _azureOptions.CallbackPath;
options.RequireHttpsMetadata = false;
options.SaveTokens = true; // set to true
}
Then you can get the ID token from httpContextAccessor:
var idToken = _httpContextAccessor.HttpContext.GetTokenAsync("id_token");
But the access token is still null . The sample shows how to use the OpenID Connect ASP.NET Core middleware to sign-in users from a single Azure AD tenant , that means you can get the ID Token which is sent to the client application as part of an OpenID Connect flow and is used by the client to authenticate the user. Please refer to document : ID tokens .
While Access tokens enable clients to securely call APIs protected by Azure . Please refer to document : Azure Active Directory access tokens .
If you want to get the access token for accessing resource which protected by Azure AD , you should use ADAL(Azure AD V1.0 endpoint) to obtain the token , see code sample(especially use OnAuthorizationCodeReceived to acquire access token):
https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore
Or use MSAL if you are using Azure AD V2.0 endpoint .

How to Consume/Validate Token Issued by AspNet.Security.OpenIdConnect.Server (RC1)?

I have followed everything I know from posts regarding how to implement AspNet.Security.OpenIdConnect.Server.
Pinpoint, do you hear me? ;)
I've managed to separate token issuing and token consumption. I won't show the "auth server side" because I think that part is all set, but I'll show how I built the authentication ticket inside my custom AuthorizationProvider:
public sealed class AuthorizationProvider : OpenIdConnectServerProvider
{
// The other overrides are not show. I've relaxed them to always validate.
public override async Task GrantResourceOwnerCredentials(GrantResourceOwnerCredentialsContext context)
{
// I'm using Microsoft.AspNet.Identity to validate user/password.
// So, let's say that I already have MyUser user from
//UserManager<MyUser> UM:
var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);
//identity.AddClaims(await UM.GetClaimsAsync(user));
identity.AddClaim(ClaimTypes.Name, user.UserName);
(await UM.GetRolesAsync(user)).ToList().ForEach(role => {
identity.AddClaim(ClaimTypes.Role, role);
});
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity),
new AuthenticationProperties(),
context.Options.AuthenticationScheme);
// Some new stuff, per my latest research
ticket.SetResources(new[] { "my_resource_server" });
ticket.SetAudiences(new[] { "my_resource_server" });
ticket.SetScopes(new[] { "defaultscope" });
context.Validated(ticket);
}
}
And startup at the auth server:
using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Data.Entity;
using Microsoft.Extensions.DependencyInjection;
using MyAuthServer.Providers;
namespace My.AuthServer
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication();
services.AddCaching();
services.AddMvc();
string connectionString = "there is actually one";
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyDbContext>(options => {
options.UseSqlServer(connectionString).UseRowNumberForPaging();
});
services.AddIdentity<User, Role>()
.AddEntityFrameworkStores<MyDbContext>().AddDefaultTokenProviders();
}
public void Configure(IApplicationBuilder app)
{
app.UseIISPlatformHandler();
app.UseOpenIdConnectServer(options => {
options.ApplicationCanDisplayErrors = true;
options.AllowInsecureHttp = true;
options.Provider = new AuthorizationProvider();
options.TokenEndpointPath = "/token";
options.AccessTokenLifetime = new TimeSpan(1, 0, 0, 0);
options.Issuer = new Uri("http://localhost:60556/");
});
app.UseMvc();
app.UseWelcomePage();
}
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
Sure enough, when I have this HTTP request, I do get an access token, but I'm not sure if that access token has all the data that the resource server expects.
POST /token HTTP/1.1
Host: localhost:60556
Content-Type: application/x-www-form-urlencoded
username=admin&password=pw&grant_type=password
Now, At the resource server side, I'm using JWT Bearer Authentication. On startup, I've got:
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Data.Entity;
using Microsoft.Extensions.DependencyInjection;
namespace MyResourceServer
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
string connectionString = "there is actually one";
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyDbContext>(options => {
options.UseSqlServer(connectionString).UseRowNumberForPaging();
});
services.AddIdentity<User, Role>()
.AddEntityFrameworkStores<MyDbContext>().AddDefaultTokenProviders();
}
public void Configure(IApplicationBuilder app)
{
app.UseIISPlatformHandler();
app.UseMvc();
app.UseWelcomePage();
app.UseJwtBearerAuthentication(options => {
options.Audience = "my_resource_server";
options.Authority = "http://localhost:60556/";
options.AutomaticAuthenticate = true;
options.RequireHttpsMetadata = false;
});
}
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
When I make this HTTP request to the resource server, I get a 401 Unauthorized:
GET /api/user/myroles HTTP/1.1
Host: localhost:64539
Authorization: Bearer eyJhbGciOiJS...
Content-Type: application/json;charset=utf-8
The controller who has a route to /api/user/myroles is decorated with a plain [Authorize] with no parameters.
I feel like I'm missing something in both auth and resource servers, but don't know what they are.
The other questions that ask "how to validate token issued by AspNet.Security.OpenIdConnect.Server" don't have an answer. I would appreciate some help in this.
Also, I've noticed that there is OAuth Introspection commented out in the sample provider, and have read somewhere that Jwt is not going to be supported soon. I can't find the dependency that gives me the OAuth Instrospection.
UPDATE I've included both of my startup.cs, from each of auth and resource servers. Could there be anything wrong that would cause the resource server to always return a 401 for every request?
One thing I didn't really touch throughout this whole endeavor is signing. It seems to generate a signature for the JWT at the auth server, but the resource server (I guess) doesn't know the signing keys. Back in the OWIN projects, I had to create a machine key and put on the two servers.
Edit: the order of your middleware instances is not correct: the JWT bearer middleware must be registered before MVC:
app.UseIISPlatformHandler();
app.UseJwtBearerAuthentication(options => {
options.Audience = "my_resource_server";
options.Authority = "http://localhost:60556/";
options.AutomaticAuthenticate = true;
options.RequireHttpsMetadata = false;
});
app.UseMvc();
app.UseWelcomePage();
Sure enough, when I have this HTTP request, I do get an access token, but I'm not sure if that access token has all the data that the resource server expects.
Your authorization server and resource server configuration look fine, but you're not setting the "destination" when adding your claims (don't forget that to avoid leaking confidential data, AspNet.Security.OpenIdConnect.Server refuses to serialize the claims that don't explicitly specify a destination):
var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);
identity.AddClaim(ClaimTypes.Name, user.UserName, destination: "id_token token");
(await UM.GetRolesAsync(user)).ToList().ForEach(role => {
identity.AddClaim(ClaimTypes.Role, role, destination: "id_token token");
});
Also, I've noticed that there is OAuth Introspection commented out in the sample provider, and have read somewhere that Jwt is not going to be supported soon. I can't find the dependency that gives me the OAuth Instrospection.
Starting with the next beta (ASOS beta5, not yet on NuGet.org when writing this answer), we'll stop using JWT as the default format for access tokens, but of course, JWT will still be supported OTB.
Tokens now being opaque by default, you'll have to use either the new validation middleware (inspired from Katana's OAuthBearerAuthenticationMiddleware) or the new standard introspection middleware, that implements the OAuth2 introspection RFC:
app.UseOAuthValidation();
// Alternatively, you can also use the introspection middleware.
// Using it is recommended if your resource server is in a
// different application/separated from the authorization server.
//
// app.UseOAuthIntrospection(options => {
// options.AutomaticAuthenticate = true;
// options.AutomaticChallenge = true;
// options.Authority = "http://localhost:54540/";
// options.Audience = "resource_server";
// options.ClientId = "resource_server";
// options.ClientSecret = "875sqd4s5d748z78z7ds1ff8zz8814ff88ed8ea4z4zzd";
// });
You can find more information about these 2 middleware here: https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/issues/185

Thinktecture Identity server v3 Google provider

I am getting issue while integration external provider i.e Google with Thinktecture identity server v3 .I am getting following error: "The client application is not known or is not authorized."
Do any one have any idea about this error.
#Whoever, it looks like you have a mismatch on the RedirectUri values in the client and server.
The RedirectUri property in the client startup defines the URI that will be called called after authentication by the identity server. The RedirectUris in the server config defines the listed of allowed URIs that can request authentication. The client startup RedirectUri must therefore be included in the server's RedirectUris list.
Looks like your client's RedirectUri is currently pointing at the server's URI. Is your client running on port 46289? If so, try changing the value of RedirectUri property in the client startup to https://localhost:46289. You might also want to try modifying the server's redirectUris value to use https rather than http, assuming that your client really is accessible over https.
Server client store:
public static IEnumerable<Client> Get()
{
return new[] {
new Client {
Enabled = true,
ClientName = "MVC Client",
ClientId = "mvc",
Flow = Flows.Implicit,
RedirectUris = new List<string>{
"https://localhost:46289/" // client home url
Client startup:
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions {
Authority = "https://localhost:44300/identity",
ClientId = "mvc",
RedirectUri = "https://localhost:46289/", //must be in server's Client.RedirectUris
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies"
});
I had this problem. The RedirectUris entry in the servers almost matched the RedirectUri in the client Startup.Configuration; all but for the trailing slash.
https://localhost:46289/
is not the same as
https://localhost:46289
When I added the slash, my login page appeared.
I've been working through the same issue but just authenticating against Identity Server (Google is next to tackle on my list). I saw the issue because the Scopes for the client weren't setup on both the Mvc and Server. To resolve the issue I added the Scopes into the Startup class (of the Mvc client) as follows:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44301",
Scope = "openid profile email roles",
ClientId = "mvc",
RedirectUri = "https://localhost:44300/",
ResponseType = "id_token",
SignInAsAuthenticationType = "Cookies"
});
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
}
}
..and also in the server's list of clients:
public static class Clients
{
public static IEnumerable<Client> Get()
{
return new[]
{
new Client
{
Enabled = true,
ClientName = "MVC Client",
ClientId = "mvc",
Flow = Flows.Implicit,
RequireConsent = true,
RedirectUris = new List<string>
{
"https://localhost:44300/"
},
PostLogoutRedirectUris = new List<string>
{
"https://localhost:44300/"
},
AllowedScopes = new List<string> {
Constants.StandardScopes.OpenId,
Constants.StandardScopes.Profile,
Constants.StandardScopes.Email,
Constants.StandardScopes.Roles
}
}
};
}
}
In relation to the OP's question with Google, it may be worth checking your scopes correlate with those supported by your app setup within the Google Developer Console too. There's a good SO post on supported scopes at Where can I find a list of scopes for Google's OAuth 2.0 API?
Hope that helps :)
Looks like client(application in which you want to have a possibility to log in with Google) is not registered in the client store. Could you, please, show your Startup Configuration?
In my case, I was not careful and was changing the values in Startup.cs under UseOpenIdConnectAuthentication (which are what the integrated web application uses to connect to itself) when I should have been changing the values in Clients.Get(), which are the allowed clients that the server has configured.
Once I fixed those, I was able to separate client and server into two applications with only some NuGet packages and UseCookieAuthentication/UseOpenIdConnectAuthentication in the client application.
You can get the error if the client is not enabled, redirect uri does not match one in the list (uses non case-sensitive exact match), if the scopes requested are not in the allowed scope list, if the flow requested does not match what is allowed (you can only have one per client) and/or if the client ids do not match.