Thinktecture Identity server v3 Google provider - thinktecture-ident-server

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.

Related

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

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.

.Net Core / Identity Server - Is it possible to AllowAnonymous but only from my client?

I have a REST API and an IdentityServer set up. I would like to be able to display items in my client from the API without having to sign in. However, I would also like to protect my API from external clients that don't belong to me. Is it possible to AllowAnonymous but only from my client?
[HttpGet]
[AllowAnonymous]
public List<Item> GetItems()
{
return new List<Item> { "item1", "item2" };
}
Edit w/ Solution
As mentioned by Tore Nestenius, I changed the grant types from Code to CodeAndClientCredentials and added the Authorize attribute to my controller so that only my client can access it.
Controller:
[HttpGet]
[Authorize]
public List<Item> GetItems()
{
return new List<Item> { "item1", "item2" };
Identity Server 4 Config File:
public static IEnumerable<Client> Clients =>
new Client[]
{
new Client
{
ClientId = "postman-api",
AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
}
};
}
CORS only works for requests from browsers, if a non browser application makes a request, then CORS will not be involved.
if you use [AllowAnonymous], then any client can access that API endpoint. Either you create separate client for the general things, perhaps using the Client Credentials flow, so that the client can authenticate, get its own token without any user involved.
Turns out this is handled by CORS.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder => builder
.WithOrigins("yourURL")
.AllowAnyMethod());
})
}

Authenticate a .NET Core 2.1 SignalR console client to a web app that uses "Identity as UI"

Using .NET Core 2.1 & VS2017 preview 2 I created a simple web server with "Identity as UI" as explained here and then added a SignalR chat following this.
In particular I have:
app.UseAuthentication();
app.UseSignalR((options) => {
options.MapHub<MyHub>("/hubs/myhub");
});
..
[Authorize]
public class MyHub : Hub
..
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:5000",
"sslPort": 0
I start the debugger which brings the browser, register a user and log in, then go to http://localhost:5000/SignalRtest (my razor page that uses signalr.js) and verify the chat works fine.
I now try to create a .NET Core console app chat client:
class Program
{
public static async Task SetupSignalRHubAsync()
{
var hubConnection = new HubConnectionBuilder()
.WithUrl("http://localhost:5000/hubs/myhub")
.Build();
await hubConnection.StartAsync();
await hubConnection.SendAsync("Send", "consoleapp");
}
public static void Main(string[] args)
{
SetupSignalRHubAsync().Wait();
}
}
My issue is I don't know how to authenticate this client ?
EDIT:
(from https://github.com/aspnet/SignalR/issues/2455)
"The reason it works in the browser is because the browser has a
Cookie from when you logged in, so it sends it automatically when
SignalR makes it's requests. To do something similar in the .NET
client you'll have to call a REST API on your server that can set the
cookie, scoop the cookie up from HttpClient and then provide it in the
call to .WithUrl, like so:
var loginCookie = /* get the cookie */
var hubConnection = new HubConnectionBuilder()
.WithUrl("http://localhost:5000/hubs/myhub", options => {
options.Cookies.Add(loginCookie);
})
.Build();
I now put a bounty on this question, hoping to get a solution showing how to authenticate the .NET Core 2.1 SignalR console client with a .NET Core 2.1 web app SignalR server that uses "Identity as UI". I need to get the cookie from the server and then add it to SignalR HubConnectionBuilder (which now have a WithCookie method).
Note that I am not looking for a third-party solutions like IdentityServer
Thanks!
I did ended up getting this to work like this:
On the server I scaffolded Login and then in Login.cshtml.cs added
[AllowAnonymous]
[IgnoreAntiforgeryToken(Order = 1001)]
public class LoginModel : PageModel
That is I do not require the anti forgery token on login (which doesn't make sense anyway)
The client code is then like this:
HttpClientHandler handler = new HttpClientHandler();
CookieContainer cookies = new CookieContainer();
handler.CookieContainer = cookies;
HttpClient client = new HttpClient(handler);
var uri = new Uri("http://localhost:5000/Identity/Account/Login");
string jsonInString = "Input.Email=myemail&Input.Password=mypassword&Input.RememberMe=false";
HttpResponseMessage response = await client.PostAsync(uri, new StringContent(jsonInString, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded"));
var responseCookies = cookies.GetCookies(uri);
var authCookie = responseCookies[".AspNetCore.Identity.Application"];
var hubConnection = new HubConnectionBuilder()
.WithUrl("http://localhost:5000/hubs/myhub", options =>
{
options.Cookies.Add(authCookie);
})
.Build();
await hubConnection.StartAsync();
await hubConnection.SendAsync("Send", "hello!");
(of course password will be elsewhere in deployment)

Restrict user from opening new tab in MVC application

How to restrict a user from opening a new tab in mvc application, we are using azure active directory authentication so by default it uses cookie & we can't disable cookie.
In order to store data we are using session to store class details and its persisted throughout the application however a new tab creates an issue as the session details are getting shared, what we can do to resolve this issue any code link will surely help.
code using AAD
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); // Authentication type is cookies
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = (context) =>
{
X509Certificate2 cert = null;
X509Store store = new X509Store(StoreLocation.CurrentUser);
// Here the code all about certification & access token
return Task.FromResult(0);
}
}
});
}

Re-challenge authenticated users in ASP.NET Core

I'm running into some issues with the authentication pipeline in ASP.NET Core. My scenario is that I want to issue a challenge to a user who is already authenticated using OpenID Connect and Azure AD. There are multiple scenarios where you'd want to do that, for example when requesting additional scopes in a AAD v2 endpoint scenario.
This works like a charm in ASP.NET MVC, but in ASP.NET Core MVC the user is being redirected to the Access Denied-page as configured in the cookie authentication middleware. (When the user is not logged in, issuing a challenge works as expected.)
After a couple of hours searching the web and trying different parameters for my middleware options, I'm beginning to suspect that either I'm missing something obvious, or this behavior is by design and I need to solve my requirement some other way. Anyone any ideas on this?
EDIT: the relevant parts of my Startup.cs look like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthentication(
SharedOptions => SharedOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// <snip...>
app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme });
var options = new OpenIdConnectOptions
{
AuthenticationScheme = OpenIdConnectDefaults.AuthenticationScheme,
ClientId = ClientId,
Authority = Authority,
CallbackPath = Configuration["Authentication:AzureAd:CallbackPath"],
ResponseType = OpenIdConnectResponseType.CodeIdToken,
PostLogoutRedirectUri = "https://localhost:44374/",
TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = false
}
};
options.Scope.Add("email");
options.Scope.Add("offline_access");
app.UseOpenIdConnectAuthentication(options);
}
And the Action looks like this:
public void RefreshSession()
{
HttpContext.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" });
}
I found a hint and the solution here: https://github.com/aspnet/Security/issues/912.
ChallengeBehavior.Unauthorized is the "key".
This post gives the current (november 2016 - ASPNet 1.0.1) workaround: https://joonasw.net/view/azure-ad-b2c-with-aspnet-core
You'll need a new ActionResult to be able to call the AuthauticationManager.ChallengeAsync with the ChallengeBehavior.Unauthorized behavior.
Once the issue https://github.com/aspnet/Mvc/issues/5187 will be sucessfully closed, this should be integrated.
I tested it and it worked perfectly well (my goal was simply to extend Google scopes on a per user basis).
Try to sign out:
public void RefreshSession()
{
HttpContext.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
HttpContext.Authentication.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
HttpContext.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" });
}