So I have a basic Setup. IdentityServer with 3 login options. Username/Password, Google login and an External Login provider. As it is right now when I run the following code:
var config = {
authority: "https://example.com",
client_id: "js",
redirect_uri: "https://example.com/callback.html",
response_type: "code",
scope: "openid profile api1",
post_logout_redirect_uri: "https://example.com/index.html",
};
var mgr = new Oidc.UserManager(config);
function login() {
mgr.signinRedirect();
}
I get redirected to the following page.
When I press login I get redirected to my login page:
This is all fine. But now I have a new requirement for the login process. They want a specific login button on the javascript client to start login with google and a specific button to login with OpenIDConnect login provider from the javascript Client.
So I could have some subpage eg. /GoogleIntegrations.html or whatever. And there I would like to have a button "Try google login", that should start loginflow with google, by redirect to the IdentityServer and then make the google redirect instantly afterwards.
Has anyone had similar usecase?
Edit1:
Account controller can be found here: https://github.com/TopSwagCode/Dotnet.IdentityServer/blob/master/src/IdentityServerAspNetIdentity/Controllers/Account/AccountController.cs
Edit2: I have tried the solution by abdusco, but I am stuck on the identity server. I don't get redirected back to my Javascript client.
eg: If I have button with: https://localhost:5001/External/Challenge?scheme=OpenIdConnect I do get redirected to the external login provider. But when I login I am stuck on the Identity Server page.
I have also tried to login with the following link:
https://localhost:5001/External/Challenge?returnurl=/connect/authorize/callback?client_id=js&redirect_uri=https%3A%2F%2Flocalhost%3A5003%2Fcallback.html&response_type=code&scope=openid%20profile%20api1&scheme=OpenIdConnect
GIF of how it looks with normal flow:
Edit3:
using the following code from comment:
var returnUrl = location.href;
var url = "https://localhost:5001/External/Challenge?returnurl=" + returnUrl + "&scheme=OpenIdConnect"
location.href = url;
throws exception. See code screenshot below
Edit4:
I was looking into another aproach, but still not entirely working as I want. On the login page on Identity, you can bypass username/password login. If I comment out that code and just redirect to my OpenIdConnect login. I get login and redirect back to client as I want, but this will then not allow me to use google or username password login.
Code looks like the following:
/// <summary>
/// Entry point into the login workflow
/// </summary>
[HttpGet]
public async Task<IActionResult> Login(string returnUrl)
{
// build a model so we know what to show on the login page
var vm = await BuildLoginViewModelAsync(returnUrl);
var context = HttpContext;
//if (vm.IsExternalLoginOnly)
//{
// we only have one option for logging in and it's an external provider
return RedirectToAction("Challenge", "External",
new { scheme = "OpenIdConnect", provider = vm.ExternalLoginScheme, returnUrl });
//}
return View(vm);
}
I found a solution myself.
So first off I created a new Callback URL for the OpenIDConnect Users. Eg. /admincallback.html
Then I can use the OIDC Usermanger javascript like so:
mgr.signinRedirect({ redirect_uri: 'https://localhost:5003/admincallback.html' });
While normal login button just use the default /callback.html
This will let me check on the Identity backend what callback is being used and based on that what login page to show. Default or instant challenge external providers. Like so:
/// <summary>
/// Entry point into the login workflow
/// </summary>
[HttpGet]
public async Task<IActionResult> Login(string returnUrl)
{
// build a model so we know what to show on the login page
var vm = await BuildLoginViewModelAsync(returnUrl);
if (returnUrl.Contains("admincallback"))
{
// we only have one option for logging in and it's an external provider
return RedirectToAction("Challenge", "External",
new { scheme = "OpenIdConnect", provider = vm.ExternalLoginScheme, returnUrl });
}
return View(vm);
}
You could create your callback url's to contain provider name like: /callback/google, /callback/oidc, /callback/azure, etc. This would let you dynamically decide which button was pressed. Instead of having a bunch of if statements for each supported provider.
This approach requires you to remember to add these new callback url's to the database. All code can be found here:
https://github.com/TopSwagCode/Dotnet.IdentityServer
This is just a project where I share all IdentityServer related stuff I learn.