Thursday, December 4, 2014

How to generate custom JWT in WSO2 API Manager 1.8.0

In this post we will discuss how to use external implementation for JWT generating logic.
Recently we introduce accessToken to generateToken() method available in AbstractJWTGenerator class which implemented TokenGenerator.
With this change custom JWT generator can generate JWT based on the API access token as well.
We didn't changed method signature of populateStandardClaims(). But followings were changed.

-TokenGenerator.generateToken(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext,String version, String accessToken) throws APIManagementException
-AbstractJWTGenerator.buildBody(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext, String version, String accessToken)
-AbstractJWTGenerator.populateCustomClaims(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext,String version, String accessToken)

New method:
public String generateToken(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext,String version, String accessToken) throws APIManagementException.


Sample CustomTokenGenerator code would be something like this. There you can implement your own claim generator.

package org.wso2.carbon.test;

import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO;
import org.wso2.carbon.apimgt.impl.token.JWTGenerator;
import org.wso2.carbon.apimgt.api.*;

import java.util.Map;

public class CustomTokenGenerator extends JWTGenerator {

    public Map populateStandardClaims(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext, String version)
            throws APIManagementException {
        Map claims = super.populateStandardClaims(keyValidationInfoDTO, apiContext, version);
        boolean isApplicationToken =
                keyValidationInfoDTO.getUserType().equalsIgnoreCase(APIConstants.ACCESS_TOKEN_USER_TYPE_APPLICATION) ? true : false;
        String dialect = getDialectURI();
        if (claims.get(dialect + "/enduser") != null) {
            if (isApplicationToken) {
                claims.put(dialect + "/enduser", "null");
                claims.put(dialect + "/enduserTenantId", "null");
            } else {
                String enduser = claims.get(dialect + "/enduser");
                if (enduser.endsWith("@carbon.super")) {
                    enduser = enduser.replace("@carbon.super", "");
                    claims.put(dialect + "/enduser", enduser);
                }
            }
        }

        return claims;

    }

    public Map populateCustomClaims(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext, String version, String accessToken)
            throws APIManagementException {
        System.out.println("************************************************************************Access Token is :"+accessToken );
        boolean isApplicationToken =
                keyValidationInfoDTO.getUserType().equalsIgnoreCase(APIConstants.ACCESS_TOKEN_USER_TYPE_APPLICATION) ? true : false;
        if(getClaimsRetriever() != null) {
            if (isApplicationToken) {
                return null;
            }else {
                return super.populateCustomClaims(keyValidationInfoDTO,apiContext,version,accessToken);
            }
        }

        return null;
    }
}


Build this class and add jar file to /repository/components/lib/ directory of the product.
Then add the element to specify which implementation should be used as the JWTGenerator.
This should come under section in api-manager.xml.
Also JWT generation should be enabled at this time.

<APIConsumerAuthentication>
....
<TokenGeneratorImpl>org.wso2.carbon.test.CustomTokenGenerator</TokenGeneratorImpl>
....
</APIConsumerAuthentication>
Restart the server with :        Linux/Unix :  sh wso2server.sh        Windows    :  wso2server.bat Then when you invoke APIs you will see access token getting printed.

4 comments:

  1. Hello Sanjeewa,

    Could you please let me know which jar files we need to use to satisfy below failure of import? And how to deploy and execute code?

    import org.wso2.carbon.apimgt.impl.APIConstants;
    import org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO;
    import org.wso2.carbon.apimgt.impl.token.JWTGenerator;
    import org.wso2.carbon.apimgt.api.*;

    Thank you.
    Sayali

    ReplyDelete
  2. Please add following dependencies to your pom file.
    And note that versions can change with API Manager product version. You can search for impl and api jars in your pack to get exact version numbers.


    org.wso2.carbon.apimgt
    org.wso2.carbon.apimgt.impl
    4.3.0-SNAPSHOT


    org.wso2.carbon.apimgt
    org.wso2.carbon.apimgt.api
    4.3.0-SNAPSHOT



    ReplyDelete
  3. Hi Sanjeewa,

    Is there a way configure multiple (application-wise) TokenGeneratorImpl classes in api-manager.xml or is it one per the WSO2 instance?

    Thanks,
    Akshit.

    ReplyDelete
  4. Hi Akshit,
    No there is no way to generate tokens per application. But like i mentioned if need you can call external service with application details and generate custom response if need. You can implement your own logic to generate application based JWT.

    Thanks,
    sanjeewa.

    ReplyDelete