What is the mechanism for setting a token validation period in Identity Server 4? Can the validation period vary for different tokens?
The Identity Server 4 documentation at http://docs.identityserver.io/en/dev/ shows a AuthorizationEndpoint with a property max_age, which is what I think I want, but the documentation does not really show it it inter-operates with the quickstart code for IdentityServerWithAspNetIdentity.
I have modified the Client object in Config.cs of the IdentityServerWithAspNetIdentity
// OpenID Connect hybrid flow and client credentials client (MVC)
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
RequireConsent = false,
ClientSecrets =
{
new Secret("LynxJournal".Sha256())
},
//RedirectUris = { "http://localhost:5002/signin-oidc" },
//PostLogoutRedirectUris = { "http://localhost:5002" },
RedirectUris = { serverConfig["MvcClientUrl"] + "/signin-oidc" },
PostLogoutRedirectUris = { serverConfig["MvcClientUrl"] },
IdentityTokenLifetime = 3600,
AccessTokenLifetime = 3600,
AuthorizationCodeLifetime = 3600,
AllowedScopes =
{
StandardScopes.OpenId.Name,
StandardScopes.Profile.Name,
StandardScopes.OfflineAccess.Name,
"api1"
}
}
This extends the life of the token to one hour where before the defaults seemed to give about 15-20 minutes. I added values for IdentityTokenLifetime, AccessTokenLifetime and AuthorizationCodeLifetime
Token lifetimes are set per client application. This includes both identity and access tokens. See client application entity.
If you are talking about session length this is set by each application upon successful authentication using IdentityServer.
Related
I have an Identity Server 4 instance running at https://localhost:5443/ and a client React.js application running at http://localhost:3000/ and making a reference to the oidc-client library in order to establish the communication. I've been following more or less this article.
The way I've configured the client (in-memory) on the Identity Server is as follows:
new Client
{
ClientId = "react-js-implicit-flow",
ClientName = "Some App name",
ClientUri = "http://localhost:3000",
AllowedGrantTypes = GrantTypes.Implicit,
RequireClientSecret = false,
RedirectUris = { "http://localhost:3000/signin-oidc", },
PostLogoutRedirectUris = { "http://localhost:3000/signout-oidc" },
AllowedCorsOrigins = { "http://localhost:3000" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"weatherapi.read"
},
AllowAccessTokensViaBrowser = true
}
and the way it looks like on the Ract.js app is like this:
In general, everything goes well. I can login and logout from the Identity Server but the issue is that here:
I get no value (it is null) and this stops the Identity server from redirecting me back to the client application right after logout. If I hard code it (http://localhost:3000/signout-oidc) it works. But for some reason it is just not available.
During the logout this is what the Identity Server logs show:
So, no error, no nothing but I still can not navigate back to the client app after logout.
You do not provide an idTokenHint (id token) with your logout request like the following:
const mgr = new Oidc.UserManager(settings);
const signoutUrl = await mgr.createSignoutRequest({id_token_hint: user.id_token});
window.location.href = signOutUrl.url;
//or
await mgr.signoutRedirect({id_token_hint: user.id_token});
//or just
await mgr.signoutRedirect();
//it will try to attach id_token internally
Lack of the token is the reason for Identityserver to skip the post_logout_redirect_url parameter.
Identityserver has to validate the parameter against the client's configuration, but without the token it can't.
What solved the issue for (me thanks to answer by #d_f) was to change something on the client side and more specifically: src/services/userService/signoutRedirect.
I'm doing a proof of concept, introducing OpenId Connect to our suite of products. After much discussion, we decided it would probably be better to have a separate, discreet Javascript application (Vuejs) for each product, rather than include them all in one monolithic SPA.
For this to work, we effectively need Single Sign-On ("SSO"). I have been using IdentityServer 4 as our IDP.
I seem to have had some reasonable success by providing multiple uris to the RedirectUris property of the relevant Client config of the Idp. So, both apps are effectively the same Client.
That does not feel right and I want to verify whether I am doing that correctly.
Here is my config for the Client config that covers the 2 SPAs (that would cover all the SPAs).
new Client
{
ClientName = "Some App",
ClientId = "appsuiteid",
AccessTokenLifetime = 330,// 330 seconds, default 60 minutes
IdentityTokenLifetime = 300,
AllowOfflineAccess = true,
RefreshTokenUsage = TokenUsage.ReUse,
RefreshTokenExpiration = TokenExpiration.Sliding,
UpdateAccessTokenClaimsOnRefresh = true,
RequireClientSecret = false,
AllowedGrantTypes = GrantTypes.Code,
AllowAccessTokensViaBrowser = true,
RedirectUris = new List<string>
{
"http://localhost:8080/authcallback.html", <-- first 2 Uris for first SPA
"http://localhost:8080/silent-refresh.html",
"http://localhost:8090/authcallback.html", <-- second 2 Uris for second SPA
"http://localhost:8090/silent-refresh.html",
},
PostLogoutRedirectUris = new List<string>
{
"http://localhost:8080/signout-callback-oidc",
"http://localhost:8090/signout-callback-oidc",
},
AllowedCorsOrigins = new List<string>
{
$"http://localhost:8080",
$"http://localhost:8090",
},
AllowedScopes = new List<string>
{
IdentityServer4.IdentityServerConstants.StandardScopes.OpenId,
IdentityServer4.IdentityServerConstants.StandardScopes.Profile,
},
ClientSecrets = { new Secret("somepwd".Sha256())}
}
Note, if I configure a separate client for each SPA, it does not work as each SPA gets redirected to the distinct consent page for that client - thus losing the SSO characteristic which we require.
Any guidance on this would be great.
Thanks
We are using IdentityServer4 to protect our APIs with EntityFrameworkCore to store configuration and operational data.
Here is our client data:
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client",
// no interactive user, use the clientid/secret for authentication
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
// secret for authentication
ClientSecrets =
{
new Secret("secret".Sha256())
},
// scopes that client has access to
AllowedScopes = { "api1" },
AllowOfflineAccess=true
},
new Client
{
ClientId = "client2",
// no interactive user, use the clientid/secret for authentication
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
// secret for authentication
ClientSecrets =
{
new Secret("secret".Sha256())
},
// scopes that client has access to
AllowedScopes = { "sup_api" },
AllowOfflineAccess=true
}
};
}
We posted request to connect/token endpoint,with following data in "x-www-form-urlencoded" format
client_id:client2
client_secret:secret
grant_type:client_credentials
scope:sup_api
and we have got the following response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjM2ZWE2MGZlNGY2NDZkYjIxZjI0Y2ExNjEzZTBmMTgyIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MTk4OTM1MTYsImV4cCI6MTUxOTg5MzU2NiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC9yZXNvdXJjZXMiLCJzdXBfYXBpIl0sImNsaWVudF9pZCI6ImNsaWVudDIiLCJzY29wZSI6WyJzdXBfYXBpIl19.cOznF6F6AL8onLZvvJaSX137P19k6doNa2BoJJTs6WY1LL47UOWoPhR7xIffQVSKyxGp4r-Z02kZrABjjyXzcdTaCR4538Pexep2sjlPobmKI0rfjR2apBSaMBVFXqDW-3VLTnMPyqicIBYjll5iS8YFGpUh0jZwq4rzNvYR4OooHssijQtkhpWxGzuokjKj8ZK1conySqEqorlaFJevY2x4jNlP3v0wpJ_6p77H4Lh12XENw4laGlrejtOkilnRaT7V8CclRGNsgPc81NLJhQZEp89cl37iQ1vLH74hCSs4MllO_eAZ_3Rmdan6QWUM1_zbcCEjGbXJM0QQ2qCpHw",
"expires_in": 3600,
"token_type": "Bearer"
}
But now, how we can test refresh tokens?
One way to do this is check if user still has access after the access token expiration time.
E.g.
At a high level this is what it would look like
Set access token lifetime to 1 minute
Run access test against API at 6 minute mark (there is a inbuilt delay when it actually expires the token)
You should assert that 401 will return, if it does then pass
Activate offline token
Run access test after 6 minute mark
Assert that you get non 401 response, if so then pass
It more testing of
I have an application that authenticates with Identity Server 4 using implicit flow. The application is separated into two separate .net core applications. One application handles the back end and the other handles serving the front end.
The back end and front end share the same scopes, api name, and authority settings.
I will be writing an integration with a 3rd party. Our back end application will call into the 3rd party application. We need to ensure that calls to the 3rd party application are authenticated. I'd like to share the access token the back end application receives from the front end and send that to the 3rd party application. I am not quite sure of the setup required to do this.
I thought that I could add a new Client to Identity Server and set it up with only the needed scopes required by the 3rd party. But in my local testing, I haven't been able to get this to work. I get an error IDX10804 Unable to obtain configuration from .../.well-known/openid-configuration - A security error occurred.
My config looks like:
new Client
{
ClientId = "thirdPartyClient",
ClientName = "thirdPartyClient",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email
},
AllowOfflineAccess = true,
AllowAccessTokensViaBrowser = true,
RequireConsent = false
},
new Client
{
ClientId = "myapplication",
ClientName = "myapplication",
AllowedGrantTypes = GrantTypes.Implicit,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "https://.../callback.html" },
PostLogoutRedirectUris = { "https://.../index.html"
AllowedCorsOrigins = { "https://..." },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Address,
"myscope",
},
AllowOfflineAccess = true,
AllowAccessTokensViaBrowser = true,
RequireConsent = false
}
Am I going about this the right way?
You haven't added redirect uri for the client thirdPartyClient. Without redirect uri client won't be valid.
RedirectUris
Specifies the allowed URIs to return tokens or authorization codes to
If you turn on detailed logging with Disable Just My code. You could see the error logs to find the actual reason
How do you request additional claims for the access token jwt in identity server 4 / auth code flow? My custom profile service always shows RequestedClaimTypes of 0 during my auth code flow signin so the resulting access token jwt has my subject claim but no firstname, lastname, or email claim.
Here are my requested scopes from the client:
"TestApi openid profile email"
Here is my client definition on identity server:
new Client {
ClientId = "authorizationCodeClient2",
ClientName = "Authorization Code Test",
ClientSecrets = {
new Secret("secret".Sha256())
},
Enabled = true,
AllowedGrantTypes = GrantTypes.Code,
RequireConsent = true,
AllowRememberConsent = false,
RedirectUris =
new List<string> {
"http://localhost:5436/account/oAuth2"
},
AllowedScopes = { "TestApi", "openid", "profile", "email" },
AccessTokenType = AccessTokenType.Jwt
}
Using https://github.com/bayardw/IdentityServer4.Authorization.Code for the test client.
I discovered that identity server will let you optionally stamp the id token with the user profile claims (instead of having to call the userinfo endpoint). You basically set a Boolean property for that particular client:
AlwaysIncludeUserClaimsInIdToken = true;
Note, you will want to request the following scopes on your auth request : (openid profile email)