Obtaining refresh_token through authentication api Auth0 - authentication

How to obtain refresh_token along with the access_token while reissuing the access_token through authentication api of auth0 using resource owner flow?
I have tried with the below code
DelegationRequestBase delegationRequest = new RefreshTokenDelegationRequest(["auth0:ClientId"], ["auth0:ClientId"],refreshToken);
delegationRequest.Scope = "openid offline_access";
delegationRequest.GrantType = "refresh_token";
var res = cl.GetDelegationTokenAsync(delegationRequest).GetAwaiter().GetResult();
But I am getting below exception
Auth0.Core.Exceptions.ApiException
with message refresh_token is not supported
Is there any other interface or method to implement the same?

Related

OpenIddict - ASP.NET Core Client - ROPC

I am trying to implement an architecture formed by
.NET Core MVC client
Auth Server with OpenIdDict
Regarding the Auth Server I should have implemented a Resource Owner Password Credentials Grant: the token endpoint authenticates the user, creates a principal and releases
access_token
refresh_token
id_token
each with claims with appropriately set destinations
The problem is the client. Wanting to implement a ROPC client, the web application must
call the token endpoint
fetch the access_token
Build a Principal cookie with related claims
How can I build a cookie with claims inside?
How do I recover the claims? The access_token is encrypted. How can I use the id_token to retrieve the claims and put them inside the cookie?
Edit:
Here the code that generate the tokens
if (request.IsPasswordGrantType())
{
var user = await _userService.FindUserByUserNameOrEmail(request.Username);
if (user == null)
return GetForbidResponse("Account non trovato.");
// Validate the username/password parameters
bool pwdCheck = await _userService.CheckUserPassword(user, request.Password);
if (!pwdCheck)
return GetForbidResponse("Password non valida.");
//Create the principal
var principal = CreateUserPrincipal(user);
//Set Scopes
SetPrincipalScopes(principal, request);
return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
And this is an example of response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhGN0EwMTI2Nzc3QzkxMDE5QTk2NEE2NDhERUE0RTAwOUQ5QkNFRUMiLCJ4NXQiOiJqM29CSm5kOGtRR2Fsa3BramVwT0FKMmJ6dXciLCJ0eXAiOiJhdCtqd3QifQ.eyJuYW1lIjoicHN5Y2hvODciLCJlbWFpbCI6ImRhdmlkZS5tYWdnaXVsbGlAZ21haWwuY29tIiwic3ViIjoiMTk1MiIsInJvbGUiOlsiVXNlciIsIlN5c0FkbWluIl0sIm9pX2F1X2lkIjoiNiIsIm9pX3Rrbl9pZCI6IjI2Iiwic2NvcGUiOiJvcGVuaWQgb2ZmbGluZV9hY2Nlc3MiLCJleHAiOjE2NDgxNDgzMjgsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0OjUwMDEvIiwiaWF0IjoxNjQ4MTQ0NzI4fQ.nCcIbLpYDCNi093uPYHH1KA7-1StRm8G4QLRp_MeEO3ixHP2syoL_nSmkwUrv2_NHrNLzbzTgn4SSaKZTVvKHbOXs89s2S3-vJD62DnB_bc2M--z2V-4txerwTK4Q1zGwV28YtJgG_lLR-KBYvi4DQPqBH0FDAy9DF72P7gmEb_xkeUTmSvzQ3MklyuYNK6youI-y5R0x_0QEFWwkpGYnHTEIj_RmaEvz3Nz3Ic_vhwOnjCOMpAE7KLO7cYT2xFiNKwbIDfsnmHnzaFhUMdzpPsvk-VyGTu35kB4ME6mQnPObWktzncdZu1wXVoYYs3NQdRzTxxJkC0Zw0YPr4jpUA",
"token_type": "Bearer",
"expires_in": 3599,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhGN0EwMTI2Nzc3QzkxMDE5QTk2NEE2NDhERUE0RTAwOUQ5QkNFRUMiLCJ4NXQiOiJqM29CSm5kOGtRR2Fsa3BramVwT0FKMmJ6dXciLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiIxOTUyIiwib2lfYXVfaWQiOiI2IiwiYXRfaGFzaCI6ImNrN2dSdnhBcnZlN3k2emd0ZWZlZ3ciLCJvaV90a25faWQiOiIyOCIsImV4cCI6MTY0ODE0NTkyOCwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NTAwMS8iLCJpYXQiOjE2NDgxNDQ3Mjh9.iFsE4eWiSfvpzTRHFWCtX-HiHXaWJ9UO7cQdTT2u-Md87jLTSB66mmBECLdYWEYFKCi-RyX3ZKAjpoW5Le2OeFsE-wqXxDaEeCIQ9t0nz1lVzdJVHq4RcaiwR1nSEkmOkAD74OzPGj7Vj3BOppUxtXHQG4ZAFCk9CxCQD2yfMwYxikvqAktslwMWoopJtMiig9KnQuhpGIGVAGaucYH2hGgswcYJQwKuN58iFEe3WC0EiNmYG1JRPWIHUukO4bVqwEZVNFSayaMfFLg3BZOvdQ3Eua60P2SYnGJcNAXYA_C571wazZN4AQdnuGHnLhud4NpwceQDrKF1tRe7uTDMxA",
"refresh_token": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJraWQiOiJDQ0QwNEJCQTg0RkUxMUE3Nzc1RjAyQjgyNEQ5OEFGNjhEREQ4MEEwIiwidHlwIjoib2lfcmVmdCtqd3QifQ.KH_P3P_DfJmbHKKdqFh2rWaItAubi00dGOkYlyIUg2twzhwAepEvwrEwwk6WVzKv1XwXCBBRqz_Bgub0ks29TauUhYfpew1d6ZPS6C4WQCehcxLsA0LmD8HADvIuW-zhTOSIqP-JdZxaWCZ_jfi61FjjmO5y4iGKXADupid4kSW7CzuBDTscPMNQFs7u6RuCxEXAwtS35vqBR81jmZe-R7b8P87hT-jDef9H_syrzaiBDFBr_-QFN7xbIdOkmvLs4upeB07knj_JoB1V9vUOL9B3CNGT-0BKrU3HHxt2b05kx4YWIsdV7kHx3191HNZh_PkouyZrt9geLcT-dTlMXA.8g0Dk4t6w7rzEarhSPN3EA.yzAcqs3GblO9hlHBZ46-loYrkwE4iqH7qxCNjS0hTO9mGHyDPBuHmiVO2oC6w8btWJkTHU20DEtCiEA1162Lk8I3oezWbyCmXXYRW1Z-HE8waTPBUvm6hcyn6RF6ey9wzG-Qn2TOAOdq8jIxXMUueM1k4UVGhvPjeY6v4FhaNdJFv4l8XvwO9jmoBRGp0uL8n_07RYlY6tyb59CIVLiSvsA_-hDYlimVEUABa27AjQNKj-3ZwWr7JRAD7TPL0Ghbtr7eWNkQrf1zrZ99kIdtxpdAUaRMGCES-qiisbuW3g3b6RwRsE97JW5BBGqs552hZ4fLf1nVHU9U6J4MLrbKWxmCmX8DH3J0y9w0mj2Exa3wUHD7AId1FD2UEdR6y86zxfa7qrfvGXeAbIVtGAPXwcnnUT-M7HtqcHgO-AtJV1Xarpe8C7vDzlRbDGGWIpcUGbD6xWQPe-sTv1jqDcxZ3CX8naKkoojohGzZCUm6IIb_ADdsmuvcVFGuHdOcqc27QDukS_x9V4x1w918Lqi0rR1vBqgAuEPffowAUvDJJIWZPb9Q8JeyE2AF8cENp3HTGNhOweHiQkdtS836_WXA_R8A2bQU2R-hXWJpk56hlN9jZ--F6H1NcO3997SSeVHWQ1YUdzuju7j4HyGxOLx3yB0QpJplG8NGfZfSB2xq-Wi2qB6mW7edj4mL1PlBxGcrphxXeyd14WAMejsKQYueD-t1lt80NmRnkqvqtPARQHTjDcKfHLSbuFddQzlc5UCgQC97bIkM8WUgWTqH8rVNRe6gzQFVID4YxSZvs-aaCtJx0xDWaPTlyceRkaNBOuh4PGDtjRLSpcoh3EtdYL39PatbOM4-2FazY5z5r1rIYaXJ4NmAanH8GwV098TmH1sPQppsxrotKX9T5OqQxucdE2wAyrGCZM4ToyetP2SoJJCcisGU1mMy5Iv26TX9N1Wonu8URGBuhDGAd0GnR2ijX1xe6EEGaTWxUaKb5m8xfByIbXarb1TV2CB8XTwdCy3G_Y5QJQw5k88S7cnTZ4Lq5saPNIvFPhGPuxgrrCFcvP1SshMLHnge5p2mqiIKGTvK1ypZeqOdMVeQeo5HvFHoLTcntPO1n07BbL2K2q9Gq3Vvx5o-jq0cfB6lC63xImII2HrpS053Mng4daU-QIKUkaKsbEflYWVyOzBe6AgNcqHRZ3zxzZRaXn8mVuGz6YjgZE4xeS6M5e0XKlSAae-sPtr6c8sEvhBQ0tHTAWdsSk-OkuLp1f6likr4BvZwwkjgC-sYPqCiCg85npvcf28qZbh1Rs85g-g9FoRfIKljU2gyTAA1MPAx8f6EMhpBaQIi.quAj1ZNggBenfSMNmyKbvKuX_lTD_YFd6viyODV_Ugw"
}
Thank you all

Microsoft Graph access token refresh

I am writing an application that uses the "OAuth 2.0 client credentials grant flow" to get an access token for calling the Microsoft Graph API. The application authenticates as itself, not on behalf of a signed in user.
I based my code off of this example from Microsoft.
This is how I initialize the GraphServiceClient:
// Read application settings from appsettings.json (tenant ID, app ID, client secret, etc.)
AppSettings config = AppSettingsFile.ReadFromJsonFile();
// Initialize the client credential auth provider
var scopes = new[] { "https://graph.microsoft.com/.default" };
var clientSecretCredential = new ClientSecretCredential(config.TenantId, config.AppId, config.ClientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
And this is how I later use it (for example):
var users = await graphClient.Users.Request().GetAsync();
My application is an API. It is not an application that runs once and done. It will be continuously running for a long time. So I am concerned about what will happen when the access token expires. How do I make sure that when I need to use the graphClient the access token will not be expired?
According to your code snippet above, I think you are using the graph SDK and using the client credential flow as the authentication.
So we are no need to generate access token here but just using the graphClient to call the graph api and gather the information you needed. And due to this mode, it won't appear the token expired situation as each time you call an api you will new clientSecretCredential before it.
And let's come back to the refresh, azure ad provide refresh token for refreshing the access token when it expired as refresh token has much longer expire time than access token, when we try to get the refresh token, we need to append offline_access to the scope when generate the access. But using client credential flow means your app requests a new token with it's own credentials, so it's no need to using refresh token to avoid making signed-in user sign in again. Using credential flow shouldn't return refresh token.
Then you may have some ideas that you insist on using refresh the expired token process, then what you only can do is generate an access token first and save the token with its expired time in some place, and using the access token as the http request header and calling graph api. Then the code should like this, but I don't think you're willing to using this kind of code, you may also refer to this document for more details:
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "your_azuread_clientid";
var clientSecret = "corresponding_client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var tokenRequestContext = new TokenRequestContext(scopes);
var token = clientSecretCredential.GetTokenAsync(tokenRequestContext).Result.Token;
//using http sender with the token
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token );
// Call the web API.
HttpResponseMessage response = await _httpClient.GetAsync(apiUri);
...
}

Web site Authentication against Web API

I have the following scenario with net core 3. A web site with a login page. This login page sends the user and password to a Web API that response with a JWT token if the credentials are correct.
How can I set now my web user as authenticated? how can I set the claims of the web user with the claims I recieve from the API token?
Is it neccessary to add any service on the startup of something similar?
Could you provide me with any basic sample of how to do it or any documentation?
Thank you
You can use cookie authentication :
In the Startup.ConfigureServices method, create the Authentication Middleware services with the AddAuthentication and AddCookie methods:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Account/Login";
});
And enable middleware in Configure :
app.UseAuthentication();
app.UseAuthorization();
And in the action which user post credential to , you can send a http request to web api with credential , web api will validate the credential and return back jwt token , your web application then decode token and sign in user like :
var stream = "[token]";
var handler = new JwtSecurityTokenHandler();
var tokenS = handler.ReadToken(stream) as JwtSecurityToken;
var claimsIdentity = new ClaimsIdentity(
tokenS.Claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties
{
RedirectUri = "/Home/Privacy",
};
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authProperties);
Depending on your front end solution, you need to figure out how to decode the JWT that you received to retrieve the values that you need.
Here are a couple of things, again depending on what you are using on the front end
C#
https://developer.okta.com/blog/2019/06/26/decode-jwt-in-csharp-for-authorization
NPM Package for SPA
https://www.npmjs.com/package/jwt-decode
Here is another good resource for JWT
https://jwt.io/
You can take the JWT you received to view the values that are in it

identityserver 4 get current user's access_token

I am having trouble getting my current user's access_token.
Here is my setup:
QuickstartIdentityServer (QIS) in aspnet core, identity and EF storage
API (API) in NodeJs. Validates jwt tokens in header against QIS.
SPA angular app that works great with QIS and API and is out of the scope of this question
In a section of the QuickstartIdentityServer (QIS) site (user details page), I would like to call an API endpoint using an access_token to authenticate the request. I am struggling to retrieve the current user's access_token from my QIS site. Whenever I call HttpContext.GetTokenAsync("access_token") I get a null value. I have seen this section of IdSrv4 documentation: https://identityserver4.readthedocs.io/en/release/quickstarts/5_hybrid_and_api_access.html?highlight=gettokenasync but it seems to apply to an MVC client and not my own identity server.
Anyone could shed some light on how to get my user's access_token ?
Thanks
EDIT
Here is a starting point to try to explain better my issue:
https://github.com/IdentityServer/IdentityServer4.Samples/tree/release/Quickstarts/6_AspNetIdentity/src/IdentityServerWithAspNetIdentity
Starting from this QIS project, I would like to get the logged in user's access token. So for instance, if I edit HomeController to add this call:
public async Task<IActionResult> Index()
{
var accessToken = await HttpContext.GetTokenAsync("access_token");
return View(accessToken);
}
I would then be able to call my NodeJS API with this token in the Auth Header.
Hope this explains better my issue.
So I managed to authenticate myself w/ my API using a dedicated Client using client credentials grant and the following call to get an access_token:
var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
var tokenClient = new TokenClient(disco.TokenEndpoint, clientId, clientSecret);
var tokenResponse = await tokenClient.RequestClientCredentialsAsync(scope);
Then I can add to my request header to API the access_token returned in tokenResponse:
using(var client = new HttpClient()) {
client.SetBearerToken(tokenResponse.AccessToken);
...
// execute request
}
The downside is that I can't "impersonate" the current currently logged on IS on API side.

Authentication and Authorization with ASP.NET Core and Service Stack

I have a ASP.Net Core MVC Web App that users needs to logon to get the id_token from the IdentityServer4 and then that id_token will be passed to webapi implemented in ServiceStack to obtain the authorization code. The subsequent call to the webapi will use the authorization code.
So far what I have read is for the Web App, it should use openid cookie token (UseOpenIdConnectAuthentication). For the webapi, it should use the bearer token. My question is how I can pass that http only cookie token from the client side browser as a bearer token in the http header. As the cookie is http only, it can't be accessed by the Javascript. Moreover, the ASP.NET Core cookie middleware encrypts the cookie, can that encrypted cookie be decrypted by the ServiceStack webapi (if the cookie is passed to the webapi)?
Am I going in the right direction? Any suggestion is welcome.
Thanks
You can find an example of your scenario here: https://identityserver4.readthedocs.io/en/release/quickstarts/5_hybrid_and_api_access.html
The authorization code is only used to get access tokens from the identity server, it is not used to authenticate to APIs.
Here is how the flow should work:
User logs in at Identity Server
Your MVC app gets an authorization code and id token
The id token tells your MVC app who the user is
The authorization code is exchanged for an access token and refresh token with identity server for the API
Now the MVC app can make HTTP calls from its backend using the access token
Authentication cookie is created and returned to user
Front-end submits the authentication cookie with every request to MVC backend, which authenticates every request automatically that hits MVC, then when you want to call the API from there, get it as shown in the docs, and attach it to your requests
I think the point you are missing here is that once the user is logged in, you will get the access token in the response as well when you land back on the client application. If you are using Hybrid Flow, on the client app we configure it as
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = "Cookies",
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
ClientId = "mvc",
ClientSecret = "secret",
ResponseType = "code id_token",
Scope = { "api1", "offline_access" },
GetClaimsFromUserInfoEndpoint = true,
SaveTokens = true
});
See the ResponseType we ask for code i.e the access code. So you need not to call or login again. Once you want to call your api just get the token like
var access_token = await HttpContext.Authentication.GetTokenAsync("access_token");
// call api
var client = new HttpClient();
client.SetBearerToken(access_token);
var response = await client.GetAsync("http://localhost:5001/identity");
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
}
else
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(JArray.Parse(content));
}
And if you using Implicit flow, your front end can get the access token using oidc-client library and user.access_token will have it.