What is the error message (if any)? Not an error. This is a “how do I” question.
I know I’m doing this insecurely. This question is trying to rectify that. I have this workflow to generate a bearer token if the expiration time has lapsed. I want to use stored username/password, and if possible, store the bearer token until it needs to be replaced.
The workflow gets the username and password, along with the current bearer token, it’s expiration from a local store.
If the bearer token is expired, it uses an http node to call the server to have it generate a new token.
Finally, it returns the valid token to the calling workflow. I use this for multiple clients, so I would like to be able to specify which credentials it will be using when I call this workflow.
The purpose of this post is to secure the credentials. Since I use this for many clients, any solution should be able to call the appropriate credentials.
Please share your workflow
Share the output returned by the last node
This is the bearer token (expired!) returned by the API server.
@russellkg Hello! If your doing this on your server like making the token, or you have control over the https server used to gen the token, you could make an authorization code the request needs to have to acsess the token.
What exactly makes you think it’s insecure, and where would you like improvement?
I would also protect where secrets are stored. The ideal approach is to keep username/password in n8n Credentials or in a secrets manager, not in Data Tables or execution outputs. For multiple clients, the workflow can receive a customer identifier and use the correct credential based on it to generate or renew the token.
I am passing a client ‘flag’ at various places. So I’ve got part of that implemented.
Mostly the reason I did it this way to start is I had to get something working, and now it’s time to go back and fix my shortcut to productivity.
As I said in my original post, the bearer token that was copied into that message is an example. It’s expired, and even if it wasn’t, you’d need to figure out which client, which tenant, and which credentials are needed with that bearer token. Either way, at this point, it returns a failed authentication. It’s not possible to authenticate or renew that token. Along with that, this exercise is specifically to get this out of my workflows.
Which gets me to the next boggle.
Once I have the server returning a bearer token to me, where do I put it for the 24 hours it’s valid for? I don’t believe the bearer token node can be edited by a workflow.
Part of the reason I did this the way I did was because I didn’t want to generate a bearer token each time I connected, and it’s not obvious what I’m supposed to do with the bearer.
@russellkg
I wouldn’t try to write back to an n8n Bearer Token credential. Those credentials are better for stable secrets, not for your case.
In that case, I would store the token in a cache layer/table with clientKey, accessToken and expiresAt, something like Redis, and create a reusable “Get Valid Token” workflow. This workflow would check if a valid token already exists for that client; if it does, return the token; if it’s expired, generate a new one, update the cache and return the new value.
Token caching via file is fine - one json file per client, named with the client key, is a clean enough pattern and it scales well.
The actual issue is credentials (email, password, accessToken) living in the workflow itself - pinned node data shows up in execution history and anyone with workflow access can see it in plain text in the workflow JSON.
** The fix I use is ENV VARS. Lload a .env file at n8n startup so the credentials are never in the workflow at all. I wrote up how I do it here:
My other post:
Short version - load a .env file via a bat/shell script at startup, set N8N_BLOCK_ENV_ACCESS_IN_NODE=false, then reference as expression, Variable Anchor like {{ $env.MOSYLE_EMAIL_CR }} etc. The UI will throw a warning saying “not accessible” but it resolves fine at runtime. Per-client you just namespace them: MOSYLE_EMAIL_CLIENT1, MOSYLE_EMAIL_CLIENT2 and so on.
http Request node uses manual header/body params to pass email, password, accessToken — any field accepting expression, so env vars work perfectly there
One thing though - env vars only load at startup, so don’t try to store the bearer token itself there. That part you’ve actually already solved with the file write. The split is: static credentials (email/pass/accessToken) go in .env, dynamic bearer token stays in the json file. Nothing sensitive in the workflow, and your existing token refresh logic keeps working exactly as is.
Actually, checking the expiry date from the token’s expiry field is not a very reliable way (the token may be revoked for another reason).
A better approach is:
Create a new Bearer-type Credential (or Header-type credentials if the field has a custom name) for each token you want to use.
Add a separate workflow to periodically check if the token is alive (e.g. ping some endpoint/fetch basic data. Just to make sure it’s alive) for each credential. Or add a sub-workflow with this checking logic to work as a proxy method, which will accept http method, url, query, body, credential name/token name to use, and call this sub WF from each parent, that should use a token
If the token is not alive (expired/invalid or for other reasons) >> call a /login endpoint to fetch a new token and update the credential via HTTP Node and n8n REST APIpatch /credentials/{id}
The method works well if you do not have a lot of tokens; otherwise, the file approach may be better.
And disable Execution history for the workflow that generates a token. Like this
Ok. After much research and some AI added in, I’ve implemented a workflow. To highlight the parameters:
I have several clients using different tenants on the Mosyle platform.
n8n doesn’t (yet?) have a way to call credentials via an expression
Multiple workflows that do the same thing with different credentials is a recipe for nightmares
I’m using UpStash to store the credentials securely.
Here’s the workflow:
I think this is decent. It uses what @tamy.santos suggests. It doesn’t implement periodically checking the tokent as @barn4k suggested. That simply hasn’t been an issue. I’ll keep it under my hat in case it becomes and issue.
I also sanitized my workflows to verify I don’t have credentials laying around, waiting for anyone to happen along.