How UseIdentityServerBearerTokenAuthentication validates the JWT token (with local mode) - jwt

I have the following code in my application, say WebApp1:
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "IdentityServerPath",
RequiredScopes = new[] { "write", "role", "all_claims" },
ValidationMode = ValidationMode.Local,
});
Caller/Client application passes the JWT token to WebApp1. How does the WebApp1 knows that the JWT token is valid? Does WebApp1 needs to know the public key of the JWT token? if not how the signature of JWT can be verified by WebApp1? Please note that I am using ValidationMode as local, so WebApp1 will not contact IdentityServer to validate the JWT token.

For the option of "local", UseIdentityServerBearerTokenAuthentication uses the discovery document (https://openid.net/specs/openid-connect-discovery-1_0.html) to dynamically download the signing materials needed to validate JWTs.
The other option of "validation endpoint" uses either the custom token validation endpoint (https://identityserver.github.io/Documentation/docsv2/endpoints/accessTokenValidation.html), or if a client id and secret is configured, then the standard OAuth2 Introspection (https://www.rfc-editor.org/rfc/rfc7662) endpoint is used to validate the token (https://identityserver.github.io/Documentation/docsv2/endpoints/introspection.html).
The last option of "both" will dynamically determine which of the two approaches described above based upon some heuristics on the incoming access token presented to the Web API.

Related

Next Auth + Next JS

I am trying to use NextAuth as auth provider for my project. I have a requirement where I have Credential based login/password. In this case when I login I have to pass the username/password to the custom API (for ex.: abc.com/auth/login). This API as success will return me a JWT for future communication to access their resources.
What I understood from NextAuth that it maintain its own session and JWT(if DB not provided). This feature works in my case but I have to maintain the JWT which the API has returned me(mentioned above). So now there are two JWT one which I received from API and the one which NextAuth has created.
My question:
Is there a way which I can use to maintain the custom JWT which I received from API?
Is there a way if API token has been expired to tempered so I can kill NextAuth session.
What is the best way to keep NextAuth Session and Custom JWT token in sync?
Thanks in advance!
Got the answer on Next-auth repo discussions itself.
This solution worked for me.
So, we can let next-auth generate the JWT token which contains the same payload as the one provided by the API (We can disable the token signature verification in the API).
Then update the next-auth configuration to have a save token in cookie has httpOnly: false so we can access the token server and client sides by adding it in the configuration:
const options = {
// ...
cookies: { sessionToken: { name: `next-auth.session-token`, options: { httpOnly: false } } },
}
After that we can use the code to get the JWT token to be passed to the API calls from the server and client sides:
import cookies from 'next-cookies'
import Cookies from 'js-cookie'
// Server-Side
cookies(context)['next-auth.session-token']
// Client-side
Cookies.get('next-auth.session-token')
Now we just need to figured out how to save my JWT token provided by my API instead of using the one generated by next-auth.
Then we will be able to reactivate the signature verification in the backend API.
You can follow the thread here

How does .net core web api jwtbearer middleware verify OpenID Connect token with authentication provider

I have been banging my head against the wall for a few days now. The solution is probably too simple to state in blogs so I ask the question here.
I am developing a .NET Core Web API which should delegate all authentication and authorization to a Keycloak identity provider server.
I have written the following code in my Startup.cs file:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.Authority = "https://idp.abc.xyz/auth/realms/master";
o.Audience = "products-api";
});
services.AddAuthorization(options =>
{
options.AddPolicy("Administrator", policy => policy.RequireClaim("user_roles", "product_catalog_admin"));
options.AddPolicy("User", policy => policy.RequireClaim("user_roles", "product_catalog_user"));
});
Now I can use Postman to request a token from the IDP and send that token to the Web API. Then the Web API validates that token but does NOT know anything about the IDP other than the URL and only makes a request to a public URL of the IDP to get some configuration.
Question:
HOW does the Web API know that the token is valid, not tampered with (created using different key), if it doesn't know anything about the IDP?
AddJwtBearer will use the options you give it to perform in memory validation of tokens. By default this involves the following actions:
Validate issuer
Validate audience
Check that the token's exp claim is not in the past (expired)
Verify the access token's digital signature
The 4th check is the most complex and by default this involves downloading token signing public keys from the IDP's JWKS endpoint, then choosing the one in the JWT's kid header. A blog post of mine has some details on how this works.
Of course you should always test the above 4 conditions and ensure that in each case API access is denied with a 401 error response that clients can code against.

REST Validating token in business API generated by authentication service

I have two different REST API’s say Authentication API & Business API hosted in Windows azure.
Authentication API is responsible for authenticating user using WsFederation or OpenID or custom authentication
Business API is responsible for executing business logic. Only legitimate user should be able to access this API.
Client will contact first Authentication API and will acquire the token and then it will pass that token to Business API.
Since client can send any token to business API. Business has to validate the token. It simply cannot trust on the token. Since token Is generated by Authentication API, how business API will validate the token.
What is a standard way to validate the token in such scenario where Authentication API and Business API are hosted separately?
Good References
Principles of Token Validation (Vittorio's blog) - Awesome article, most of the information is generic so applies with or without Azure AD, and it's coming from a very knowledgeable author of course
Manually validating a JWT access token in a web API - This one is specific to validating an Azure AD issued token. Has complete code implementation too. You don't need to do exactly this, because your validation will depend on token format/claims that you use but may provide a helpful reference.
You can look at how token validation is recommended for applications secured by Azure Active Directory as a case study (and may be some other systems as well), then decide what works best for your case.
Brief explanation on how Azure AD example is relevant.. as validating received token is required just like in your case
When you develop any web API (or web app) secured by Azure Active Directory and use bearer token based authentication, the way things flow is very similar to what you explain above with your 2 APIs (just for understanding purpose, your authentication API is doing what Azure AD token endpoints would do.. i.e. provide a valid token).
To access the secure web API, calling application/client first interacts with Azure AD endpoints to get a relevant token for required resource, then it sends a request for actual resource along with the token in Authorization header to the web API. Now, the first thing web API does is to validate this token and only if everything is correct continue with execution to eventually return a response. I hope this matches at a high level with your flow.
What to validate?
1. Token Signature
The key used to sign the issued token is uniquely associated to the issuing authority, so nobody else can issue a token with your Authority's signature.
a. This helps to check that the token was in fact issued by Azure AD (or in your case your trusted STS, using the Authentication API you mention).
b. This also makes sure that since the token was issued and till it reached your web API, no body has tampered with it. If any attempt is made to change any information in the token, the signature will break.
2. Token Claims
This will depend on what claims/information you send as part of the token (for example, if same Authentication API issues tokens for multiple different APIs, then something like audience and issuer might make sense for you as well. Token validity time period using something like nbf and exp below are also pretty generic)
Taking Azure AD issued tokens as example here are the important ones that should be validated:
audience claim (aud), to verify that the token was intended to be given to your application
not before (nbf) and expiration time (exp) claims, to verify that the token has been received within it's validity period
issuer claim (iss), to verify that that token was in fact issued by the said authority. Notice this is a second way, apart from signature for the same purpose and generally both signature and issuer check are used together. (See Vittorio's blog)
nonce, as a token replay attack mitigation
tenant claim (tid), to verify the tenant. This is useful in case of multi-tenant applications.
Sample JWT Token from Azure AD
Actual Value: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1N... (a long encoded string continues) Decoded Value (you can check this easily using a website like https://jwt.ms or https://jwt.io):
{
"aud": "https://service.contoso.com/",
"iss": "https://sts.windows.net/7fe81447-da57-4385-becb-6de57f21477e/",
"iat": 1388440863,
"nbf": 1388440863,
"exp": 1388444763,
"ver": "1.0",
"tid": "7fe81447-da57-4385-becb-6de57f21477e",
"oid": "68389ae2-62fa-4b18-91fe-53dd109d74f5",
"upn": "frankm#contoso.com",
"unique_name": "frankm#contoso.com",
"sub": "deNqIj9IOE9PWJWbHsftXt2EabPVl0Cj8QAmefRLV98",
"family_name": "Miller",
"given_name": "Frank",
"appid": "2d4d11a2-f814-46a7-890a-274a72a7309e",
"appidacr": "0",
"scp": "user_impersonation",
"acr": "1"
}
How to do token validation?
Make use of standard libraries as much as possible. See the code implementation sample Manually validating a JWT access token in a web API. This one makes use of JwtSecurityTokenHandler.ValidateToken Method (JwtSecurityToken). Your case will depend on your token format/implementation etc.

Renew access token and protect static files

I have question regarding setup of access token renewal/refresh. Our Setup:
Implicit flow
Angular SPA using bearer token for API
Thin MVC frontend serving cshtml containing SPA
Short access token (10min)
20 min Idsrv cookie sliding (used as activity timeout)
The application has to apply to some strict security rules and intellectual property.
We need to renew the access token before it expires and API returns 401.
I’ve looked at the oidc-client-js to handle that. But that would remove the option of authenticating the static files like we do today, since there would no longer be a cookie for the MVC app.
Is there a way of securing them, or is that just something that we have to accept when building a SPA with OpenID Connect?
If you would like to enforce authorization on static files then this needs to be done by server-side code. Since your client is using an MVC backend, my recommendation would be to use the Hybrid Flow in conjunction with the Katana OpenID Connect middleware. You may then pass on any tokens you would like to use from the server-side code to your SPA via your view (cshtml).
The middleware required is available on NuGet:
install-package Microsoft.Owin.Security.Cookies
install-package Microsoft.Owin.Security.OpenIdConnect
The following snippet allows for configuration in your OWIN pipeline (taken and slightly altered from this tutorial):
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44319/identity",
ClientId = "mvc",
RedirectUri = "https://localhost:44319/",
ResponseType = "code id_token",
Scope = "openid offline_access",
SignInAsAuthenticationType = "Cookies"
});
Using this flow, you are no longer given tokens immediately but will need to exchange the auth code returned ("code" grant type) for a pair of tokens being the:
access_token (the one you are already receiving in implicit flow)
refresh_token (this can be used at the token endpoint to renew the access_token)
The main things to note about the above configuration are response type and scope.
Response type is no longer just asking for tokens (implicit) but now asks for code.
Scope includes "offline_access" scope which will return the refresh_token.
Like this we have solved both your access token expiry problem and have begun to solve your static asset problem by moving authorization to the back-end. To help you with the next part I would need to know how you are serving your assets as there are different ways depending on whether you are using OWIN to serve or IIS.

Process JWT token using JWKs Endpoint

I receive two JWTs: an OpenID Connect ID token (id_token) and an Access Token (access_token). The situation with OpenID is more or less clear - I can validate it using a JWKS Endpoint: https://smth.com/JWKS.
as in example (https://bitbucket.org/b_c/jose4j/wiki/JWT%20Examples):
HttpsJwks httpsJkws = new HttpsJwks("https://smth.com/JWKS");
HttpsJwksVerificationKeyResolver httpsJwksKeyResolver = new HttpsJwksVerificationKeyResolver(httpsJkws);
jwtConsumer = new JwtConsumerBuilder()
.setVerificationKeyResolver(httpsJwksKeyResolver)
.setExpectedAudience(...)
.setExpectedIssuer(...)
.build();
The question is how to proceed with the Access Token. I can extract from it the userId and userDetails, but I guess I need also to validate it?
If I try to validate the Access Token the same as for the ID Token, I am getting this error:
UnresolvableKeyException: Unable to find a suitable verification key for JWS w/ header {"alg" : "RS256", "kid":"1"}
And indeed there is no key for "kid" : "1", Also this value "1" seems kind of strange?
Am I doing something totally wrong?
It sounds like you are implementing the role of OpenID Connect client or Relying Party. The two tokens, ID token and access token, serve different purposes and should be handled differently by the client. The ID token is intended for the client and enables authentication of the end-user at the client. The client must validate the ID token (verify the signature and validate claims like exp and aud, etc.) before allowing the end-user in. The access token, however, is for the client to use to access resources or APIs but is not directly intended for the client to consume or validate. The access token is opaque to the client and the client shouldn't care or know about its details. In fact, access tokens aren't always JWTs. In OpenID Connect, the access token is used to call the user info endpoint (with the HTTP header, Authorization: Bearer [access token]) to get more claims/info about the end-user.
The value of "1" for the kid is totally legal but it is referring to a key that the AS/OP and the user info endpoint know about somehow. It is not a key at the OpenID Connect JWKS endpoint. "1" isn't a key that the client needs to know about because the client isn't supposed to directly verify the access token.