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.