apiauthenticationjwtdotnetnukedotnetnuke-9

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


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 :)


Solution

  • 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.