thomann061 / fmrest

A Node.js wrapper for Filemaker's Data API (REST API)
https://thomann061.github.io/fmrest/
MIT License
28 stars 4 forks source link

Code 952 - Invalid FileMaker Data API token (*) #24

Open dani-phillips opened 1 year ago

dani-phillips commented 1 year ago

Edit: I guess after analyzing the fmrest.js in /lib there doesn't seem to be any functionality for automatic refreshing of the access token. Was this in a previous version?

I have an app that sets up a new instance of fmrest and provides an onTokenRefresh option that is supposed to refresh the token automatically when necessary.

So I wanted to test this, so I opened up the web page and loaded a customer's file, and let it sit there for about 30 minutes or so before trying to refresh the page. When I refreshed the page, I received this error in the console:

{
    "messages": [
        {
            "code":  "952",
            "message": "Invalid FileMaker Data API token (*)"
        }
    ]
    "response": {}
}

The app is very simple, here is the code for it:

require('dotenv').config();
const express = require('express');
const fmrest = require('fmrest');

const app = express();
const port = 3000;

let token = null;

// Create a single fmrest instance
const fm = new fmrest({
    host: process.env.FM_HOST,
    database: process.env.FM_DATABASE,
    layout: process.env.FM_LAYOUT,
    user: process.env.FM_USERNAME,
    password: process.env.FM_PASSWORD,
    auth: 'basic',
    onTokenRefresh: (newToken) => {
        console.log(`Token refreshed, newToken value: ${newToken}`);
        token = newToken;
    },
});

// Login to FileMaker
fm.login()
    .then((data) => {
        console.log('fm:', JSON.stringify(fm, null, 3));
        token = data?.response?.token;
        console.log(`Token value: ${token}`);

        app.get('/customer/:customerId', async (req, res) => {
            try {
                const customerId = req.params.customerId;

                if (!customerId) {
                    return res.send('No customer ID provided');
                }

                let request = fm.createRequest().where('ID').is(customerId);
                fm.find({ requests: [request], options: { token: token } }).then(
                    (data) => {
                        console.log(JSON.stringify(data, null, 3));
                    },
                );

                return res.send('Customer ID: ' + customerId);
            } catch (err) {
                res.status(500).send(err.message);
            }
        });

        app.listen(port, () => {
            console.log(`Listening on port ${port}`);
        });
    })
    .catch((err) => {
        console.error(`Error logging in to FileMaker: ${err}`);
    });

Am I doing something wrong, or does fmrest not refresh the token, or are my expectations of how it refreshes the token incorrect? I've been using ChatGPT to help me figure it out, but so far I haven't had any luck and ChatGPT says my code is correct and should refresh the token automatically.

thomann061 commented 1 year ago

Hi, there is no onTokenRefresh option for a new fmrest object.

thomann061 commented 1 year ago

What you could do, is call the login method, every time you run a query...

The more complex design is to refresh the token once it expires, which currently, is not setup.

dani-phillips commented 1 year ago

What you could do, is call the login method, every time you run a query...

The more complex design is to refresh the token once it expires, which currently, is not setup.

Would calling the login method if multiple users are hitting the /customer endpoint cause any issues with tokens since there is only one instance of fmrest handling all the calls?

If that won't cause any issues then I will just call login every time I run the query, I'm only going to be running that find query and an update query, but this will be open to our customers and there could be a lot of traffic at once for it.

If it would cause issues then I'll just roll my own token refresh system and only login when the token is invalid.

thomann061 commented 1 year ago

Tokens expire after an hour, so at a minimum you would have to login every hour. If you have a rapid amount of connections within an hour, yes it would be more efficient to only call login after an hour is passed. To handle a lot of traffic, look into queues (bull) or load balancers.