Reaching an api from an Auth0 rule

Hi everyone,
we are a company which need to reach our api from a rule to be able to populate tokens with our own data, so the global subject is about how you authenticate from a rule to reach your internal api.

We found an answer here in this post How do I call my API from a rule? , it’s what we did previously during the time we moved our internal user authentication into Auth0 and fortunately this script did not last for too long because it was costing us a fair amount of money.

At this time, we tried what was described here https://auth0.com/docs/rules/cache-resources , to mitigate the authentication cost and store in the global cache, the token we issued, but after some testing it appeared this cache is really short. It is described in the doc that it can goes away at any time, but it’s really too quick to solve the token cost mentioned earlier.

It seems obvious to use an Auth0 app to secure your own api calls from a rule but the token generation cost could go quickly high and I see no real storage possibility in rules.

Considering all of this what should we do to have a secured connection between Auth0 and our app without spending money just for a synchronization call ?

Thank you.

Hello, @anthony.hamon - welcome back to the Auth0 Community.

I think that in this case, your application should be pushing to your API, rather than Auth0 pushing to your API. Otherwise, it’s going to be a very costly operation for refreshing a user’s profile, which you already get after authentication via the /userinfo endpoint or an ID Token. That way, you can also have a long-lived machine to machine token in your server that you can use for these operations - instead of issuing them during each authentication, you issue them every X hours or days, depending on how frequently you want your server to authenticate/store the token.

Have you considered pushing the info to your API from your application instead of from a Rule?

1 Like

Hi thank you for your answer.

Yes it’s what we were thinking at first. In fact, we already do this for some user informations. Unfortunately, because of how the system is designed internally, the informations we need can’t be easily synchronized and we also need a way to talk to our system on both side to populate some information to keep things running.

Hey, @anthony.hamon,

In that case, the only option left would be to do it from within the Rule. There is another, much more risky option that I wouldn’t take, but you can hardcode the M2M token and manually change it before it expires, every interval of time. However, if you forget or are delayed once, all your authentications would fail.

At this point, it’s either going to come from Auth0 directly (Rule), or from your application (pushing it to the external datasource). I don’t see any other solutions - maybe someone else has any other ideas?

1 Like

Hi,

In that case, the only option left would be to do it from within the Rule

What do you mean ?

Hi there,

I was suggesting that, at this point, there are two options:

1.- Go back to the original solution which you had build, which works inside a Rule, generating a token for the call, it then caches it, and then makes the call to your external API
2.- Implement a new solution so that the application can post to the API instead of the Rule posting to the API

1 Like

Ok right, but the first solution is not possible as the cache is too short and the second one, we can’t to this at the moment.

After looking around, I found it’s possible to access the rule configs using the management api and it seems the storage is large enough for a value (I was quite surprised), it’s convenient because configuration is injected in each rule. So I created a rule for testing purpose that store the value the first time in the settings and check the JWT expiration time before issuing a brand new one

What do you think of that solution ?

function (user, context, callback) {

const axios = require("axios");
const ManagementClient = require("auth0@2.27.0").ManagementClient;
const jsonWebToken = require('jsonwebtoken@8.5.0');
const moment = require('moment@2.11.2');

const isExpired = (accessToken) => {
    if (!accessToken) {
        return true;
    }

    return moment.unix(
        jsonWebToken.decode(accessToken).exp
    ).isBefore(moment().substract(5, "minutes"));
};

const fetchAccessToken = () => {
    const url = `https://${clientDomain}/oauth/token`;

    return axios
        .post(url, {
            client_id: configuration.appClientId,
            client_secret: configuration.appClientSecret,
            grant_type: "client_credentials",
            audience: configuration.appAudience
        })
        .then(res => res.data.access_token)
        .catch(err => err);
}

const saveCredentials = (credentials) => {
    const client = new ManagementClient({
        domain: configuration.mgmtDomain,
        clientId: configuration.mgmtClientId,
        clientSecret: configuration.mgmtClientSecret,
    });

    return client.setRulesConfig(
        { 'key': 'credentials' },
        { 'value': credentials },
    );
};

return (async () => {
    try {
        if (!isExpired(configuration.credentials)) {
            return callback(null, user, context)
        }

        const internalApiAccessToken = await fetchAccessToken();

        await saveCredentials(internalApiAccessToken);
    } catch (e) {
        console.log(e);
    }
    return callback(null, user, context);
})();

}

I think this could be a viable solution that would allow you for longer storage than the cache, but be super careful to ensure that your validation is always working, and that your token is always valid.

1 Like

The condition seems pretty, it’s only a matter of checking if the expire time is correct. To ensure no race condition occurs, I’ve added a 5mn time window (code updated).

The only concerns I have is about the rule settings, what is the limit of this storage ? Will it be limited at a point or will it remains like that ? I’m wondering because when I see client application metadata in clients, you have a 255 characters limit.

There shouldn’t be a limit. As a matter of fact, I’ve just tried with a 2200 value and I was able to print it successfully.

1 Like

Right, I think it’s fine.
Thank you for your answers.

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.