Search code examples
oauth-2.0jwtopenidoneloginscim

OneLogin: Get JWT Token programmatically


We successfully integrated a static frontend application to connect to a Spring-Based backend API using JWT Tokens with https://github.com/IdentityModel/oidc-client-js.

var userManager = new Oidc.UserManager({
    authority: 'https://openid-connect-eu.onelogin.com/oidc',
    client_id: config.oidc_client_id,
    redirect_uri: config.oidc_redirect_uri,
    response_type: 'id_token token',
    scope: 'openid profile email',

    filterProtocolClaims: true,
    loadUserInfo: true
});

var user = {};

async function _login() {
    user = await userManager.getUser();
    if (!user || user.expired) {
        var hash = parseUrl(window.location.hash),
            id_token = hash.id_token;

        if (id_token) {
            user = await userManager.signinRedirectCallback();
            initAfterLogin(user);
        } else {
            userManager.signinRedirect();
        }
    }
    else {
        initAfterLogin();
    }
}
function initAfterLogin() {
    console.log('JWT Token: ', user.id_token)
}

We kan use the JWT Token as Bearer authentication call for our backend, and the validation succeeds.

Now, we're trying to find a way to automatically test our backend calls, so we need to get the JWT token from a NodeJS runtime (POSTman Pre-Request Script).

const getJwtTokenRequest = {
    url: 'https://openid-connect-eu.onelogin.com/oidc/token',
    method: 'POST',
    header: [{
            key: 'Content-Type',
            value: 'application/x-www-form-urlencoded'
        },{
            key: 'Authorization',
            value: 'Basic '+Buffer.from(client_id+':'+client_secret).toString('base64')
        }
    ],
    body: {
        mode: 'urlencoded',
        urlencoded: [{
                key: 'username',
                value: test_user
            }, {
                key: 'password',
                value: test_password
            }, {
                key: 'client_id',
                value: client_id
            }, {
                key: 'grant_type',
                value: 'password'
            }, {
                key: 'scope',
                value: 'openid profile email'
            }, {
                key: 'response_type',
                value: 'id_token token'
            }
        ]
    }
};

var getToken = true;

if (!pm.environment.get('OIDC_JWT_Token') ||
    !pm.environment.get('OIDC_JWT_Expiry')) {
    console.log('Token or expiry date are missing')
} else if (pm.environment.get('OIDC_JWT_Expiry') <= (new Date()).getTime()) {
    console.log('Token is expired')
} else {
    getToken = false;
    console.log('Token and expiry date are all good');
}

if (getToken === true) {
    pm.sendRequest(getJwtTokenRequest, function (err, res) {
        console.log(err ? err : res.json());
        if (err === null) {
            console.log('Saving the token and expiry date')
            var responseJson = res.json();
            pm.environment.set('OIDC_JWT_Token', responseJson.id_token)

            var expiryDate = new Date();
            expiryDate.setSeconds(expiryDate.getSeconds() + responseJson.expires_in);
            pm.environment.set('OIDC_JWT_Expiry', expiryDate.getTime());
        }
    });
}

However, the /token api endpoint only returns an access_token, not an id_token (JWT token).

{
    "access_token": "MzEzNzJlMmYtZmFhMS00MXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-fn7fOiqgao-EiPp-PKrtMHqnBafdtbKU-DpodVl9YQqTwxDNTgE0k6w",
    "expires_in": 3600,
    "token_type": "Bearer"
}

If I search through the OneLogin API, it seams that we can only get the id_token from an explicit authorization flow via the frontend.


Solution

  • Only being able to get an id_token from an explicit authorization flow is typically the case since the id_token represents a user authentication event and as such the user should be present.

    There may be a way to use the Resource Owner Password Credentials grant type to do the same in a non-browser scenario but that depends on the features that OneLogin provides.

    If they do you'd have to request the token using grant_type=password and provide scope=openid.