Unable to pass dynamic values to config records

148 Views Asked by At

I have a requirement to pass a JWT client assertion to the oauth2 client credentials grant config record. I'm passing the parameter as the optional parameter. But this parameter has to be generated each time the token endpoint is called for an access token. Therefore I did something like the following.

http:OAuth2ClientCredentialsGrantConfig oauth2Config = {
    tokenUrl: "https://*****/oauth2/token",
    clientId: "*******",
    optionalParams: getJWT(),
    clientSecret: "*****",
    credentialBearer: oauth2:POST_BODY_BEARER
};

Here, the getJWT() method returns a map with the JWT.

function getJWT() returns map<string> {
    string jwt = // logic to generate the JWT
    map<string> jwtAssertion = {
        "client_assertion" : jwt
    };
    return jwtAssertion;
}

This works only once. When the access token returned by the token endpoint expires and when the token endpoint is called again for the access token, the getJWT() method does not get called. Therefore, I suppose the new request is going with the old JWT, hence the request fails.

Is there a way to pass a dynamically changing value as a parameter to the http:OAuth2ClientCredentialsGrantConfig record?

1

There are 1 best solutions below

0
On

You can achieve this by writing a custom ClientOAuth2Handler and using it as described in the imperative approach section.

Your custom handler should check for the exp value of client_assertion and create a new http:ClientOAuth2Handler with a new client_assertion when it expires. You can get an idea from the below code.

import ballerina/http;
import ballerina/oauth2;
import ballerina/jwt;
import ballerina/time;

client class CustomClientOAuth2Handler {
    private http:ClientOAuth2Handler? oauthHandler = ();
    private string? jwt = ();

    public function init() returns error? {
        self.jwt = self.getJWT();
        self.oauthHandler = check self.getOauth2Handler();
    }

    remote function enrich(http:Request request) returns http:Request|error {
        boolean isJwtExpired = check self.isJwtExpired();
        if isJwtExpired {
            self.jwt = self.getJWT();
            self.oauthHandler = check self.getOauth2Handler();
        }

        http:ClientOAuth2Handler oauthHandler = check self.oauthHandler.ensureType();
        return oauthHandler->enrich(request);
    }

    private function getJWT() returns string {
        return ""; // your jwt logic
    }

    private function getOauth2Handler() returns http:ClientOAuth2Handler|error {
        string jwt = check self.jwt.ensureType();
        return new ({
            tokenUrl: "https://localhost:9445/oauth2/token",
            clientId: "FlfJYKBD2c925h4lkycqNZlC2l4a",
            clientSecret: "PJz0UhTJMrHOo68QQNpvnqAY_3Aa",
            credentialBearer: oauth2:POST_BODY_BEARER,
            optionalParams: {client_assertion: jwt}
        });
    }

    private function isJwtExpired() returns boolean|error {
        // your logic to check jwt assertion expirty
        string jwt = check self.jwt.ensureType();
        [jwt:Header, jwt:Payload] [_, payload] = check jwt:decode(jwt);
        int? assertionExpiryTime = payload.exp;

        [int, decimal] currentTime = time:utcNow();
        return assertionExpiryTime !is () && assertionExpiryTime <= currentTime[0];
    }
}