Can't obtain token due to unauthorized_client error - c#

I'm composing a demo on how to obtain a token from IDS4 using Postman.
The request for password token is taken from IDS4's page.
[HttpGet("token")]
public IActionResult GetToken([FromHeader] string user, [FromHeader] string pass)
{
string tokenEndpoint = "https://localhost:44300/connect/token";
HttpClient client = new HttpClient();
Task<TokenResponse> tokenResponse =
client.RequestPasswordTokenAsync(new PasswordTokenRequest
{
Address = tokenEndpoint,
ClientId = "client",
ClientSecret = "client_secret",
Scope = "MemberApi.full",
UserName = user,
Password = pass
});
TokenResponse toko = tokenResponse.Result;
if (toko.IsError)
return Ok(toko.Error);
return Ok(toko.AccessToken;
}
The clients are set up as follows.
private static IEnumerable<Client> GetClients => new[]
{
...
new Client
{
ClientId = "client",
ClientSecrets = { new Secret("client_secret".Sha256()) },
ClientName = "Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://localhost:5000/security/credentials" },
PostLogoutRedirectUris = { "http://localhost:5000/index.html" },
AllowedCorsOrigins = { "http://localhost:5000", "https://localhost:44300" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"MemberApi",
"MemberApi.full",
"MemberApi.limited"
}
}
};
The API resources are set up as the following shows.
private static IEnumerable<ApiResource> GetApis => new[]
{
new ApiResource
{
Name = "MemberApi",
DisplayName = "Members' API",
ApiSecrets = {new Secret("MemberSecret".Sha256())},
UserClaims = {JwtClaimTypes.Name, JwtClaimTypes.Email, JwtClaimTypes.Role},
Scopes = {new Scope("MemberApi.full"), new Scope("MemberApi.limited")}
}
};
As far I can tell I followed the suggestions in the docs. I've tried to compare with the examples, too. Despite that, I get stuck on the error saying unauthorized_client. What can I be missing?

The client request is not allowed in this flow:
AllowedGrantTypes = GrantTypes.Implicit
Forget client.RequestPasswordTokenAsync. You don't need it and you can't use it. In the implicit flow only the user knows the password. It is out of reach for the client.
Assume IdentityServer runs on one domain: https://idp.mydomain.com and the client runs somewhere else: https://mvc.mydomain.com
When the user hits a secured page on the mvc client, the user is routed to IdentityServer where the user logs in. There the user enters the credentials and if succesful the user is returned to the client as a known identity.
Depending on the flow the client eventually ends up with at least an access token. This token is important because that allows the client to access the resource on behalf of the user. It is like an entry ticket.
Based on the access token the resource now knows WHO wants to access the resource. The access token has one claim that makes this distinction, the 'sub' claim. Without this claim the client has no access to the resource in this flow.
In your configuration the client is allowed to access the 'MemberApi' scopes, but it needs the user's consent before it actually can access the resource.
If you want to retrieve a token start with the easiest flow there is, the client credentials flow.
That's the flow where there is no user at all. The client (as in piece of software) can login using the clientid + secret. When configured properly this will result in an access token.
Now the client can access the resource without any user interaction. The identity token is not available as there is no user. The 'sub' claim is missing. The refresh token is not supported in this flow, it doesn't need it. The client can request a new token using the credentials.
If you want to know how the refresh token works, in a hybrid flow the user logs in and in addition (if scope=offline is configured) a refresh token is returned.
As an access token is only valid for a short time (depends on the expiration time) a new token must be acquired. For this the refresh token should be used. The refresh token allows the client to request a new access token without requiring user interaction (offline access).
The new access token is used until it expires and a new token must be requested. Until the refesh token itself expires, but that can be configured.
In the implicit flow there is no refresh token, but the access token does expire all the same. So you'll need another way to refresh the token. For that you can use something like a silent token renew implementation.
For terminology please read the documentation.
Please note the various flows. It all depends on the circumstances. Is there a user or not, is it a browser application, is there a front-channel, back-channel, is offline access required, can the client keep a secret? Things that need to be considered before choosing a flow.
When a flow is chosen, you need to configure the allowed grants for clients. A client using client credentials cannot access the resource if only an implicit grant type is allowed.
IdentityServer is mostly about configuring clients and resources. Take a look at the samples to see the different flows and how they are configured.

The client is only allowed to use Implicit Flow to acquire token for accessing the resource which protected by Identity Server :
AllowedGrantTypes = GrantTypes.Implicit,
But your client is using the Resource Owner Flow :
This grant type is suitable for clients capable of obtaining the
resource owner's credentials (username and password, typically using
an interactive form). It is also used to migrate existing clients
using direct authentication schemes such as HTTP Basic or Digest
authentication to OAuth by converting the stored credentials to an
access token.
If you are using SPA application , you should use Implicit Flow to obtain tokens without exposing end user credentials to a third party.
Generally , you have three apps : client app , identity server(with user db) and api . When using Implicit Flow :
Client will redirect user to identity server app, identity server provides UI to let user enter their credentials .
After user enter their credential , identity server will validate the credential in DB/configuration file . Of course you can also config the external login in identity server .
After validate the credentials , identity server will issue ID Token and access token(if scope includes API resource) back to your client app ,according to the callback url in client's OpenID Connect configuration .
Client app will validate and decode the ID token and sign-in user . You can use SDK or directly handle the process manually .
If you get the acess token , you can keep the access token in session cache , it can be used to access the protected resource until it is expires .

Related

Client is unauthorized to retrieve access tokens using this method or client not authorized for any scope requested API Directory C#

I am getting the following error when trying to access the directory api by getting a list of users
Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"unauthorized_client", Description:"Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested.", Uri:""
Based on my previous googling efforts and reading stack overflow I am not sure what is causing this. As far as I am aware I have everything set up correctly. I have it setup to use the drive api in a very similar fashion and that works perfectly.
My service account does have domain wide delegation which is why I think it may have something to do with the second part of the error. Any ideas what could be causing this?
protected async virtual Task<DirectoryService?> GetDirectoryService()
{
if (currentDirectory == null)
{
string[] scopes = new string[] { DirectoryService.Scope.AdminDirectoryUser };
var initializer = new ServiceAccountCredential.Initializer(configuration["GoogleServiceAccount:AccountEmail"]){Scopes = scopes, User = configuration["GoogleServiceAccount:UserEmail"] };
var cred = new ServiceAccountCredential(initializer.FromPrivateKey(configuration["GoogleServiceAccount:SecretKey"]));
currentDirectory = new DirectoryService(new BaseClientService.Initializer { HttpClientInitializer = cred, ApplicationName = "DriveAPI" });
}
return currentDirectory;
User = configuration["GoogleServiceAccount:UserEmail"]
User is the user on your domain that you want to delegate as not the service accounts email address.
update
Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested
This error message in my exprence normally means that you are using code that does not match the type of credetinals you are using.
There are serval types of authorization, service account, Oauth installed and oauth web (lets ignore mobile for now). The code used for these credentials is different.
So if you use a service account key file with code designed for an Ouath2 installed app. You will normally get "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested"
The code I normally use for delegation with a service account is as follows. it looks similar to yours so i'm inclined to agree that you are using service account code. Which means to me you are probably using the wrong key file. I would double check. Open it it should say "type": "service_account".
// Load the Service account credentials and define the scope of its access.
var credential = GoogleCredential.FromFile(PathToServiceAccountKeyFile)
.CreateWithUser("user#mydomain.com")
.CreateScoped(new[] {DriveService.ScopeConstants.Drive});
My suggestion is to now double check and ensure that you are using the service account key file from google cloud console that was created by a user on your domain, and that you configured domain wide deligation for and have added the admin sdk scopes for remember the OAuth Scopes for admin have to be set, as well configuring an authorized user.

Get Microsoft accessToken silently

I'm trying to connect to Graph API and get user access token.
My problem is that I don't know how to connect to Graph API with credentials silently (without browser).
I currently use MSLogin() for get access token but it open a browser where you can authorize an AzureAD app to get some access to your account. A library in Java is litteraly what I want in c# https://github.com/Litarvan/OpenAuth
I need something like: MSGraph.ConnectAsync(email, pass).getAccessToken();
Here my current code (Through a browser)
private const string ClientId = "520f6e8e-xxxxxxxxxxxxxxxxxxxx";
private string[] scopes = { "https://graph.microsoft.com/user.read" };
private static AuthenticationResult authResult;
public static IPublicClientApplication PublicClientApp;
private async Task<AuthenticationResult> MSLogin()
{
PublicClientApp = PublicClientApplicationBuilder.Create(ClientId).WithRedirectUri("msal520f6e8e-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx://auth").Build();
authResult = await PublicClientApp.AcquireTokenInteractive(scopes).ExecuteAsync();
return authResult;
}
If you are using Microsoft Graph .NET Client Library you can check documentation with example how to implement username/password authentication flow.
string[] scopes = {"User.Read"};
var usernamePasswordCredential = new UsernamePasswordCredential("username#domain.com", "password", tenantId, clientId);
var graphClient = new GraphServiceClient(usernamePasswordCredential, scopes);
var me = await graphClient.Me.Request().GetAsync();
You can use AcquireTokenByUsernamePassword() for that, see MSDN.
Note however that Microsoft discourages usage of this flow and depending on your AzureAD setup there might be restrictions (i.e. you can aquire tokens only within a certain IP range etc).
Well, you can get the access token silently but not at the first time, First a user must authorize your app by going through Microsoft's Login flow and for your subsequent calls to Microsoft, you can get the access token without the intervention of user.
I would just give a basic idea, without focusing on a specific SDK that you might be using. For which, you can decide which ever method suits your needs.
I assume, you already have your credentials and desired scopes with you, otherwise you need to obtain those.
Formulate a proper URL using the credentials you obtained, plus you need to add an extra scope in the URL which is offline_access. Then you need to redirect the user to Microsoft for the initial authorization.
If the user logs in successfully, Microsoft will redirect the user back to your website with an Authorization Code.
Grab that Authorization Code and exchange it for an Access Token using /oauth2/{version}/token api.
You will receive a response from above call which will contain an Access Token along with a Refresh Token. You need to store the refresh token somewhere for future use.
Now comes the interesting part.
Using the refresh token, you can renew the access token when it expires without user's intervention. You can use oauth2/v2.0/token api with parameters:
client_id={your_client_id}&scope={your_scopes}&refresh_token={refresh_token_obtained}&grant_type=refresh_token&client_secret={your_client_secret}
The resultant response would look something like this:
{
"access_token": "new access token",
"token_type": "Bearer",
"expires_in": 3599,
"scope": "your scopes",
"refresh_token": "refresh token",
}
REF: https://learn.microsoft.com/en-us/graph/auth-v2-user#authorization-request

How to Authenticate two subdomain by one login in IdentityServer?

I have an IDP server implemented by Duende IdentityServer assume which is hosted on idp.com and there are two separate ReactJS applications hosted on app.mysite.com and profile.mysite.com and they are using JWT token for authentication and authorization process. now when I login into app.mysite.com through idp.com profile.mysite.com is un unauthenticated and needs another login. I use the same client configuration for both of these sites. I know there are some methods such as using an IFRAME inside client code to share the JWT token between these two app but I am looking for a built-in approach inside the Identity server to solve this issue?
First of all, if you have 2 CLIENTS, you should configure 2 separate configurations for both of them.
Afer separation of clients you should rely on cookie set on idp.com after first authentication. (Good to know - How to setup cookie authentication basic cookie authentication: https://learn.microsoft.com/pl-pl/aspnet/core/security/authentication/cookie?view=aspnetcore-6.0)
Anyway, if you configured IdentityServer properly, it handles cookie authentication "out-of-the-box" - so probably the only thing you have to do is to Signin the user.
AuthenticationProperties props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(LoginOptions.RememberMeLoginDuration)
};
var issuer = new IdentityServerUser(user.SubjectId)
{
DisplayName = user.Username
};
await HttpContext.SignInAsync(issuer, props);
When the youser want to login to second application, after start of the flow (eg. code flow) and redirect to the idp.com, idp.com knows that the user is already signed-in (cookie) and should immediately generate token and redirect back to the return url.
If you need you can adjust custom behaviours using IProfileService.

IdentityServer4 - Delegated access tokens for clients

In IdentityServer4 you can specify an extension grand to enable delegated access tokens for users, so if a webservice needs to call another webservice during a request from a user, it can request a new access token from the IdentityServer with a valid scope and audience. My issue is, that this grant is thought to be used "on behalf of the interactive user", which leads to my question:
If my client calls a webservice which needs to call another webservice during the request, how can i create a delegated access token?
I tried to modify the example from the documentation, but the extension grand expects a token from a user, which holds a "sub" claim, and not from a client, which does not hold a "sub" claim.
The client is a daemon application, so it runs fully automated and without any user interaction, and is authenticated with the client credentials flow.
To clarify what i mean:
Here we see an use case, if a user is present:
User accesses a UI
UI redirects the user to the identity server to authenticate (With the Authorization Code Flow + PCKE). The UI gets the access token back
The UI calls an WebApi A with the access token
The WebApi A needs to access the WebApi B, but the access token was meant for WebApi A. Therefore the WebApi A asks the IdentityServer for a delegated access token to access WebApi B.
The IdentityServer provides the delegated access token.
The new access token is passed along to the WebApi B.
Here we see the same use case, but no user is present and a daemon application does the same thing:
The deamon appliaction authenticates against the IdentityServer with the Client Credentails Flow and gets the access token back
The deamon appliaction calls an WebApi A with the access token
The WebApi A needs to access the WebApi B, but the access token was meant for WebApi A. Therefore the WebApi A asks the IdentityServer for a delegated access token to access WebApi B.
How to get the IdentityServer to provide a the delegated access token for the client?
The new access token is passed along to the WebApi B.
For machine to machine (Service to service) communication you typically use the client credientials grant. This allows services to communicate even if no user is present. The userid (Subject) is typically included in the API calls that is protected using this flow.
See this article
The communication between WebApi-A and WebApi-B can be done using client credentials flow and here you don't need to pass any access token from the user. Instead you pass the subjectId(userID) and optionally some additional claims as part of the API calls between A and B. This way is much simpler and the benefit is that A-B can communicate without any user involved (for example to do workflow style communication in the background).
I have found the solution to my issue. You can extend the given example implementation of the delegation grand and extend it in a way, that a delegation token is issued for a client:
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
var oldToken = context.Request.Raw.Get("token");
if (string.IsNullOrEmpty(oldToken))
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var result = await _validator.ValidateAccessTokenAsync(oldToken);
if (result.IsError)
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return;
}
var sub = result.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
if (sub != null)
{
// The old token had a user context
context.Result = new GrantValidationResult(sub, GrantType);
}
// The "magic" is the part below
else
{
// The old token had a client context
var client = result.Claims.FirstOrDefault(c => c.Type.Equals("client_id", StringComparison.Ordinal));
if (string.IsNullOrWhiteSpace(client?.Value))
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient);
return;
}
context.Request.ClientId = client.Value;
context.Result = new GrantValidationResult(new Dictionary<string, object>());
}
}

Web Api OWIN - How to validate token on each request

I have two applications
Client application build on ASP.NET MVC
Authentication server build on Web API + OWIN
Have planned authentication as follow
For user login client app will make a request to authication server with logged in credential.
Authication server will generate a token and will send back to client application.
Client application will store that token in local storage.
for each subsequent request client app will attached token kept in local storage in request header.
NOW, ON SERVER SIDE OF CLEINT APP I NEED TO VALIDATE THAT TOKEN COMES WITH EACH REQUEST IS NOT TEMPERED.
Please suggest me how to validate token in each request as i don't know the key the OWIN has used to generate the token.
Is is right to write code to validate token on client app or it should be on authication server.
I am planning to shift all user management code like register user, change password to authentication server so than we can re-use it for different client app- is it right design practice?
So far i have wrote below code to just to create a POC.
=========================OWIN configuration========
[assembly: OwinStartup(typeof(WebApi.App_Start.Startup))]
namespace WebApi.App_Start
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = false,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider(),
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new
OAuthBearerAuthenticationOptions());
}
}
}
==============================oAuth Provided========================
public class SimpleAuthorizationServerProvider: OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
using (AuthRepository _repo = new AuthRepository())
{
IdentityUser user = _repo.FindUser(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
Please help,
Thanks,
#Paul
Please suggest me how to validate token in each request as i don't
know the key the OWIN has used to generate the token.
Your current setup, were you have added the app.UseOAuthBearerAuthentication() to the owin pipeline, will authenticate the user from the bearer token which is passed on each request for you.
The current user can then be found via HttpContext.Current.User.
Use the Authorize attribute to then decide which users are authorized on certain endpoints.
Here's an example where users with the role "user" are allowed to access
[Authorize(Roles="user")]
public class ValuesController : ApiController
{
}
Is is right to write code to validate token on client app or it should
be on authication server.
NO, you don't validate the token in client, if your user credentials are wrong you wont get a token at all. That's all you need to know.
And also, why should you want to validate the token in the client?
I am planning to shift all user management code like register user,
change password to authentication server so than we can re-use it for
different client app- is it right design practice?
Reusing a token provider is common. Why invent the wheel for every application? Build one great, or use a third party, and reuse it across your applications.
Use JSON Web Tokens (JWT) and claims identities, not random tokens that require keeping track of the issued tokens.
A JWT is like a passport issued by a trusted authority. The passport is signed/stamped, and you can verify that it was issued by this trusted authority and that it has not been tampered with. That means, the integrity of the access-right claim present in the token can be verified without keeping state anywhere. The only communication that needs to happen between the trusting application and the authority is an initial (secure) download of the authority's public key (used for signing the tokens).
It's also advisable that you use a standard claims schema, like OpenID Connect ( http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims )
A good book on the topic, which helped me a lot getting an understanding of all these concepts, can be found here: A Guide to Claims-Based Identity and Access Control.
One way to verify a token has not been tampered is to sign it using an asymmetric key pair, Identity Server uses this approach as seen here.
In your case if you are rolling your own authentication you will need to implement this yourself, and check on every request probably in a custom middleware that the token is valid.
If you create, sendback, save in localStorage and every thing about JWT Token as correct, you have to know that many ways are in .Net that you can to controlling per request.
Server side controlling:
If you are using Web API Core, in core you can create Middleware that runs as pipline in run time, and you can give context and check token that requested, for more infomation check: This.
If you use of Asp.net MVC, you can use ActionFilter in MVC(Asp.Net-Core have more advance ActionFilter too), that each requests goes through on and you can check every thisng abount request, for more information check: This.
ClientSide Conftolling:
After that you give Token after log in from server side, you have to save data in localstorage that your browser check per request that data, they advantage are the Expireation and every like this issue in token save in localstorage and you and browser can use of this for more information check: This.
GoodLuck.

Categories