ASP.NET Core React Template get access-token - asp.net-core

Is there a way to get the access token from identityserver4, preferably in the Login.cshtml.cs post function. I am using the default react with authentification template (asp.net core 3.1) from visual studio. Thank you!

You can't get the issued tokens in Login.cshtml.cs post function .
That is because Asp.net Identity credential validation logic is fired before Identity Server's token issue logic . In OnPostAsync event of Login.cshtml.cs , the identity system will check user in database and sign in user using :
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true);
If user validation passed , it will redirect to local url like /connect/authorize/callback?client_id=react&redirect_uri=https%3A%2F%2Flocalhost%3A44362%2Fauthentication%2Flogin-callback&response_type=code&scope=reactAPI%20openid%20profile&state=xxxxx&code_challenge=xxxxx&code_challenge_method=S256&response_mode=query , that url in fact is OpenID Connect Authorzation Code Flow(PKCE) request . After redirecting , identity server 4 middleware will handle the code and token request and at last issue tokens . So that in OnPostAsync function you can't get the tokens .
If you want to get the tokens , you can get tokens from identity server's built-in events like TokenIssuedSuccessEvent , you can also get tokens from React client side , in which event/place to get tokens is based on your requirement .

Related

Identity Server 4, External providers and Web API

I’m in process of developing system which consists from such parts:
- Some services under gateway (Ocelot)
- Mobile client (iOS)
- Identity Server 4
Mobile client hasn’t been prepared yet, so I use Postman for emulating requests from it. My problem is implementation of Authentication with External providers, like Google. It’s my first experience of using IS 4, so I have some misunderstanding and difficulties. Excuse me, if my question is too abstract or if I miss smth obvious.
I successfully deployed IS 4 using all this tutorials and it works with Password Credentials flow in a proper way: I request IS for access token, sending user credentials, it returns token and I can successfully use it for access to my API methods.
Situation with External Providers are different. I’ve overviewed this tutorial (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-3.1) and some other and add code from it to the IS project. I can successfully log in with Google, using a button on that IS4 web-page which goes with IS 4 Quickstart UI template. But no chance to work with API. As I understand in such workflow client-app should go for a token not to my IS as in example with a local user, but to the Google Auth provider. And I emulated it with Postman and got a strange access_token which has no data and it_token which contains username, email and so on. I try to use this id_token with requests to my API. The result is always 401.
Where I’m wrong? How should I build requests to API with token from Google? Or I have misunderstanding and there should be another flow: client goes to IS with specific request, IS goes to Google and then returns proper token to Client?
Here is configuration of authecation on the side of Web API app:
private void ConfigAuthentication(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.Audience = "k_smart_api";
});
}
Here is config of Google-Auth on the side of IdentityServer:
services.AddAuthentication().AddGoogle(opts => {
opts.ClientId = "My google client Id";
opts.ClientSecret = "my google client secret";
opts.SignInScheme = IdentityConstants.ExternalScheme;
opts.SaveTokens = true;
});
This is how I get Access Token:
postman exampple
The tokens you get back from Google, is only used to Authenticate the user in Identity Server. Then after Identity Server receives those tokens, it sign-in the user and create new tokens (ID+access) that are passed to your client. you should look at using the authorization code flow in your client to authenticate the user and to get the tokens. then use the access token received to access your API.
do remember that the tokens received from Google are not used to give access to your APIs.

Azure ADB2C multiple Web APIs authentication

My scenario is related to the authentication of two or more web APIs from the same MVC Web App in which ADB2C is configured.
I have created two web apis in Azure ADB2C and granted permissions of both the web apis into ADB2C MVC web app. However whenever I tried to obtain the access token, it is giving me the access token for one web api but not giving the access token for the second one.
I want to know whether this scenario is possible in ADB2C or not?
Thanks.
One access token could be used to access by one resource(web api) . If you want another resource's access token , you can use refresh token(if exists) to get the new token :
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token
If using MSAL.NET ,after initial token acquisition , you can invoke AcquireTokenSilent, asking for the api scopes you need :
// Retrieve the token with the specified scopes
var scope = AzureAdB2COptions.ApiScopes.Split(' ');
string signedInUserID = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
IConfidentialClientApplication cca =
ConfidentialClientApplicationBuilder.Create(AzureAdB2COptions.ClientId)
.WithRedirectUri(AzureAdB2COptions.RedirectUri)
.WithClientSecret(AzureAdB2COptions.ClientSecret)
.WithB2CAuthority(AzureAdB2COptions.Authority)
.Build();
new MSALStaticCache(signedInUserID, this.HttpContext).EnablePersistence(cca.UserTokenCache);
var accounts = await cca.GetAccountsAsync();
AuthenticationResult result = await cca.AcquireTokenSilent(scope, accounts.FirstOrDefault())
.ExecuteAsync();
MSAL will look up the cache and return any cached token which match with the requirement. If such access tokens are expired or no suitable access tokens are present, but there is an associated refresh token, MSAL will automatically use that to get a new access token and return it transparently.
You can click here for code sample .

Implement OpenIdDict auth backend(Asp.Net core) to be able to auth with model entity and LinkedIn authorization

The goal is to be able to login in mobile app(react native) with:
in app username and password
"Login with LinkedId" feature.
I've researched a lot on this topic, and read the Kévin Chalet's(#Pinpoint) blog series and also cloned the sampels from: https://github.com/openiddict/openiddict-samples
I've created test server app:https://github.com/Jamaxack/OpenIdConnectAuthLinkedIn
I'm able to test the authorization to LinkedIn with https://oidcdebugger.com but now, I'm confused. Without https://oidcdebugger.com how can I test the LinkedIn authorization? for example with Postman? For my case what Auth flow should I use?
options.AllowImplicitFlow()
.AllowPasswordFlow()
.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow();
Thanks in advance.
You can use Authorization Code Flow to login using Linkedin and request permission from the member .
If using Postman , you can try below steps :
Add a new request , click the Authorization , choose OAuth 2.0 as TYPE , and set Add authorization data to to Request Headers . If you want to inspect the authorization headers and parameters that Postman generates, click the Preview Request button.
Click the Get New Access Token button . Input the correct callback url, auth url, token url , client id, client secret and scopes , callback url should match the one register in linkedin application portal .
Now you should now see a screen prompting you to login to your LinkedIn account. After click Allow in Application Authorization Confirmation page , you will get token in Postman .
Making a Get request to api https://api.linkedin.com/v2/me with token as authorization bearer token header , and you will get the correct response from linkedin API endpoint .

How to change default callback of the Microsoft authentication provider login?

In my ASP.Net Core app, I have implemented Microsoft External Login. I now wish to override the default login callback, which is listed by documentation to be https://localhost:5001/signin-microsoft, if of course running on localhost and on that port. The instructions on here then state that the callback override would be something like this: https://contoso.azurewebsites.net/.auth/login/microsoftaccount/callback.
I am a bit confused on where the callback is meant to be implemented. At the moment I have ExternalLoginCallback() callback method implemented in a base Controller class. But from looking at the above example, it doesn't look like it should be part of a controller.
Should the callback be inside Startup.cs, a Controller, or some other file I am not currently aware of?
The instructions on here then state that the callback override would be something like this: https://contoso.azurewebsites.net/.auth/login/microsoftaccount/callback.
That is related to built-in authentication and authorization support in Azure App service . Do you host your app in Azure App service ?
If yes :
If you enable the Authentication and authorizationfeature of the app service , that means you are using the built-in authentication and authorization support in Azure . That feature will take over the authentication and authorization of you application , that means authentication and authorization still works even you delete the external Azure AD authentication codes in your application . Then you could just :
Use Authentication and authorizationfeature of the app service , delete the Owin Microsoft Account authentication middleware related codes .
Disable Authentication and authorizationfeature of the app service, use Microsoft Account external login( Microsoft.AspNetCore.Authentication.MicrosoftAccount package) .
If no :
Then you should follow document : Microsoft Account external login . You can config the callback url by :
microsoftOptions.CallbackPath = "/home/about";
But if you are using the ASP.NET Identity template with Microsoft Account external login . After Microsoft authentication , asp.net will check whether user's identity exists in database . Since ASP.NET Core 2.1 and later provides ASP.NET Core Identity as a Razor Class Library. If you want to redirect user to another page after authentication , you can :
Scaffold Identity in ASP.NET Core projects: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.2&tabs=visual-studio
After that ,modify the redirect url in Areas.Identity.Pages.Account.Login.cshtml.cs:
public IActionResult OnPost(string provider, string returnUrl = null)
{
returnUrl = "/home/contact";
// Request a redirect to the external login provider.
var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return new ChallengeResult(provider, properties);
}

IdentityServer4 with LDAP/AD authentication without UI

I'm currently working on a project where I'm trying to set up a service based on IdentityServer4 (https://github.com/IdentityServer/IdentityServer4) that authenticates users by querying a local Active Directory via LDAP.
To achieve that, I also included the IdentityServer4.LdapExtension (https://github.com/Nordes/IdentityServer4.LdapExtension) in my project. The working example from the repository works fine (https://github.com/Nordes/IdentityServer4.LdapExtension/tree/master/Sample/IdentityServer) - but the custom logic is part of the UI, and I need my service to operate without any UI.
Simply adding
.AddLdapUsers<ActiveDirectoryAppUser>(Conf.GetSection("ldap"), UserStore.InMemory)
as described in the documentation does not change the request pipeline, as the provided login/validation methods are never executed - they are only triggered with calls from the UI (AccountController). However, as I said, I don't want to integrate any UI in this service and rather use the interface which the Token-Endpoint already provides (POST request with client_id and client_secret, response with JWT).
Is there a way to integrate LDAP authentication without rewriting big parts that work out-of-the-box as desired?
From your question it sounds like you already have a username and password. Note client_id != username and client_secret != password. client_id is the identity for a client application.
The grant type you are trying to use is called Resource Owner Password when using the authorize endpoint or password when using the token endpoint.
This grant type is used to support legacy systems and is not recommended for new development.
The code that you want to executed to authenticate a user is in LdapUserResourceOwnerPasswordValidator.cs and it should be executed if you pass the correct parameters to the token endpoint:
POST /connect/token
client_id=yourclientid&
client_secret=yourclientsecret&
grant_type=password&
username=yourusername&password=yourusernamespassword
See token endpoint documentation: https://identityserver4.readthedocs.io/en/release/endpoints/token.html
You can use Identity Model to help you make the token request:
var response = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
{
Address = "https://demo.identityserver.io/connect/token",
ClientId = "yourclientid",
ClientSecret = "yourclientsecret",
UserName = "yourusername",
Password = "yourusernamespassword"
});
This is documented here https://identitymodel.readthedocs.io/en/latest/client/token.html