Verifying a JWT that DNN (DotNetNuke) created in a microservice - api

I'm playing around with DNN 9 and it's implementation of JWT at the moment.
Their implementation is here - https://github.com/dnnsoftware/Dnn.Platform/tree/development/DNN%20Platform/Dnn.AuthServices.Jwt
I'm wanting to write microservices in Docker containers that all look back to DNN's SQL. However, I need to understand how to verify the JWT that will be sent via the client to make sure it hasn't been tampered. DNN's web api implementations do this automatically. The problem is I don't see how I can verify that the token is valid because there is no 'secret' that i have to add.
I would want to get the JWT from the DNN enpoint and use this in a microservice which isn't running with DNN but will be able to read the data from the DNN database.
Could anyone provide any input?
Thanks :)

If the services have access to the DNN database then you can use the validation as implemented by the referenced code.
It seems that the tokens are not real JWT tokens, in the sense that they are self-contained, though they are not real reference tokens either. The tokens are persisted in the database, but contain public data as well.
How this is implemented: the token is identified by a sessionId and the secret is a concatenated string, converted to byte array:
var secret = ObtainSecret(sessionId, portalSettings.GUID,
userInfo.Membership.LastPasswordChangeDate);
The data is a JWT. It contains a Header, a Payload and a Signature.
From the received token first the Header (and scheme) is validated. Then the RAW token is read, expiration is verfied and the existence of the SessionId is checked, which is added as claim (TokenId).
The final step is to lookup the user from the store (cache / database), using the SessionId:
private UserInfo TryGetUser(JwtSecurityToken jwt, bool checkExpiry)
{
// validate against DB saved data
var sessionId = GetJwtSessionValue(jwt);
var ptoken = DataProvider.GetTokenById(sessionId);
When the SessionId is not found, the token is not valid. Again expiration is validated.
And finally the received data is compared to the persisted token, line 423:
if (ptoken.TokenHash != GetHashedStr(jwt.RawData))
This should prevent the token from being tampered.
This means for you that you can use the same code for your microservices, provided that the services have access to the DNN database. Call ValidateToken(), which will return the username when valid or null when invalid.
An alternative is to publish your own JWT tokens like I described here. You can create a central API or use a fixed, shared secret. E.g. a certificate that is available to the microservices. In that case you are dealing with self-contained JWT tokens which can be validated using the default validators. And you don't need access to the database.

Related

Implementing public API keys with microservices

For most client applications and UI approaches JWTs seem to be a good way to carry tokens for an OAuth based approach. This allows decoupling of a User/Auth service and the services that are actually being accessed.
Given this architecture
My question is: in the case of public APIs (ie Github or Slack) where a bearer key is generated with specific roles. How is that key authorized in a microservice architecture? Do those types of keys just require that the Auth service gets queried with every request?
Could an API gateway mitigate this? I would like to understand if a solution exists where there is minimal communication between services. Thank you!
Normally, this is solved using scopes. The scopes are permissions given to a user to do certain operations,for example there will be a scope for read a repository, another for update it, another one for delete etc..
These scopes are tied to the token and normally are requested by the user himself or added automatically depending on the user type. And the same as the authentication process, they could be included in the token itself coded as a claim in a jwt or they could be requested or checked by calling an oauth server when one operation is requested.
The advantages of include them in jwt is that there is not need to call an external server every time an operation is requested so there is a lower latency and less bandwith is required, also you remove a point of failure. Obviously if this solution is used the token must be properly signed or even encrypted to avoid possible manipulations.
However it has also drawbacks, and the most dangerous one is that the token cannot be revoked because this information cannot be included in the token and the service that check if the token is valid only can access the data contained in the token itself. Because of this, this kind of tokens are normally issued with a little expiry time so in case of the token is stolen, the validity of it will be very limited

Auth0: Managing authentication on Lambda functions

Current Implementation
My current application utilizes Vue.js + Auth0 on the frontend.
Vue.js utilizes AWS API Gateway, POST/GET methods are sent via:
https://xxxx.execute-api.us-east-1.amazonaws.com/dev/
On the API Endpoints that require authentication I have a "jwtRsaCustomAuthorizer" Authorizer. Which is documented here.
Remaining Concern
However is validating IF the token is valid enough? In this scenario I want to make a POST function that will do two things:
Update the users app_metadata
Save data associated to user
How do I KNOW User id auth0|123456 is who they say they are?
With the JWT being validated by the Authorizor, do I know the token hasn't been manipulated? E.g. if I just decode the passed data, can I assume the userID is valid?
The short answer is: You do not really care in the frontend. Validation of the token normally happens via the backend, which is in your case through the jwtRsaCustomAuthorizer you were talking about. If the backend trusts the token it returns data, and if it does not it returns an authorisation error.
Your backend, and in particular jwtRsaCustomAuthorizer, does validate that the content of your JWT token is valid and trusted. A JWT token consists of three parts. The first part describes the algorithm used. The second part is the payload, which contains the claims, a nonce, an issuer and an expiration date. The third part is used to verify if the JWT token is issued by a trusted party by using a secret and generating a signature with it. In your case you are using RS256 with a private and public key pair.
Since the first two parts of the JWT token are used to generate the signature, you cannot change the algorithm or the payload without invalidating the signature. Since RS256 uses assymetric encryption using a public and private key pair, you can either verify the JWT token by performing the same steps using the private key and comparing the newly generated signature against the signature in the JWT token, or in case of your api endpoint, using the public key to decrypt the signature and checking that against the first two parts of the JWT token.
jwtRsaCustomAuthorizer ensures that the JWT token was created by auth0 by checking the JWT token against the public key that is provided by auth0. If the signature matches the payload, it means that the issuer must have had access to the private key, which is only available to the issuer. This allows you to trust the payload.
You can find more information via jwt.io and this stackoverflow question on the difference between hs256 and rs256.

Should Name Claim remain omitted in JWT Access Token with IdentityServer4 (using Identity) and ASP.Net Core API?

While configuring my IdentityServer4 (using Identity) resource owner grant flow with an asp.net core API backend, I got to thinking that perhaps the "Name" claim should remain omitted in the JWT access token for user security? This claim is not available with out of the box behavior of IS4.
Previously, I had been adding in the "Name" claim for the access token in my IS4 Config.cs file as follows:
var claims = new List<string>
{
JwtClaimTypes.Name
};
return new List<ApiResource>
{
new ApiResource("api1", "Auth API", claims)
};
I was doing this because it allows a straightforward approach to get a logged in user's ClaimsPrincipal.Identity.Name for user look up inside a Controller action.
var name = User.Identity.Name;
var user = await _userManager.FindByNameAsync(name);
However, IS4 access tokens (when using Identity) include the user's GUID id in the "Sub" claim. With this, we can also look up a user using the following:
var userId = User.Claims.FirstOrDefault(u => u.Type == "sub").Value;
var user = await _userManager.FindByIdAsync(userId);
I know there is slightly more processing with the LINQ query (hardly anything tbh), but I was thinking it might be of worth to protect a user's username (email address in my situation) if an access token ever fell into the wrong hands. Especially since JWT's are so easy to decode with the likes of jwt.io.
Do you guys agree or disagree? Or am I looking at this the wrong way and missing something?
JWT usually contain the public data and it is self-contained. i.e. You don't need to communicate with a backend server to construct user's identity. You should prevent the token fell into wrong hand by using https. Also, you should balance your token validity window(usability vs security) and use a nonce for maximizing the security.
I don't think 'name' should be omitted from claim collection. A valid use-case for what you are doing is that you need to make sure that changes to your user store immediately reflect in your web API. In the case of a self-contained token, if you change the 'name' in the data store, the user will not see that change until he was issued a new token. In this case use of a 'reference token' might be a good option.
Also, It looks like you are directly accessing user store from the web API. While you might have valid reasoning behind this, Idea of using token based authentication is to delegate authentication to external party(Identity Server). So common pattern is to
Include every public data that you require in the web API in the
access token.
If token getting too big, include a subset of claims in the token and query user info endpoint when required.
Use reference tokens if you have valid reasons to do so. But this will affect the performance as it will require back channel communication with identity server.

Is using Laravel api_token authentication not like storing password in plain text?

I want to validate my RESTful API using token authentication. Two key options provided are https://github.com/tymondesigns/jwt-auth and Laravel's own inbuilt token authentication.
I'm unable to make jwt-auth work for me even if it looks the most promising, so I decide to check on Laravel's implementation.
It is pretty straightforward. Create an extra field api_token in users DB, generate a random string and store it against the users record IN PLAIN TEXT, then any request the user sends they should append the api_token, which you shall authenticate by checking its existence in the DB. Just that.
Isn't that like storing passwords in plain text because anyone who happens to have access to the DB is as good as authenticated? Isn't there an outright security risk there? Someone help me understand this one.
Also, how does one handle things like invalidating the token, giving the token an expiry period, and such?
for Similar Case I am not using any external plugin, while Laravel already ship a project called Lumen which is best suitable for Restfull web service,
I am storing the encrypted hash string as api_token in the user table,
and in my mobile application i let the users authenticate by username password first time and then i store the decrypted token in the mobile to maintain the user state for subsequent api calls, key point is i am storing the decrypted user token in the mobile and whenver i receive the token in server, i do comparison to match both of them using the same encryption function i have used before,...
in this case you have to come up with your own encryption algorithm since you need to use the same algorithm to decry-pt in the client,
or else an easy way is to copy the user password hash string in the api_token field and store the user password in the client side,
but you have to make sure the security of the client application,
if you consider native android, i will use sharedpreference in private mode which is secure....
if(Hash::check($password,$user->password)){
$response['success'] = 1;
$response['message'] = 'You have Connected to Server Successfully';
$response['api_token'] = $user->api_token;
}else{
$response['success'] = 0;
$response['message'] = 'Authentication Unsuccessful';
$response['api_token'] = '';
}

REST authentication / authorization

I need some advices on how to secure my application:
I have a REST service, using Spring MVC 3
I have my client application, using Ext GWT 2.2
Users credentials are available on the server side only.
SSL available
REST services should only be used by authentificated users.
I have read about HTTP Digest , token based authorization, oAuth etc, but I need some clarification and advices on how to secure my application, and which methods are the best in my case.
here is the methodology we created for our applications, works very well, and is very secure.
this is a very conceptual explanation, there is a lot of code that backs this up, FYI
When user authenticates or creates account, the server returns an x.509 certificate, base64 encoded, that is unique to for the user. The server stores a copy.
Everytime the client needs to access the REST API, client creates a JSON string comprised of the following.
The Users Unique ID (UserID)
A GUID or UUID, that guarantees this call is unique,(CallID) (protects against replay attacks)
A Dictionary (collection of Key/Value) of each parameter of the rest call
we then encrypt that string with the x.509 public key, and encode it back to base64 string, and take this encrypted value and add the UserID to a json object we call the token.
we then put the token into header of each call, and call it something like: X-Auth-UserToken
On every call the server takes the token, looks up the users certificate based on the userID, then verifies that the encrypted part of the token can be decrypted with the private key that the server holds for the user.
once decrypted, the server takes the CallID and verifies that it is unique, against its own calllog db.
if it checks out, the user is authenticated.
once the user is authenticated, you can apply your own authorization rules based on the users uniqueID.
of course, all the above is over SSL.
let me know if you need me to drill down on any parts.