Integration Tokens
How a machine gets its own long-lived credential for your catalog — issuing an offline token, naming it, seeing what it did, and revoking it when the system it belonged to is retired.
Why a machine needs its own credential
An ERP that publishes products into your catalog every night has to prove who it is on every call. The obvious shortcut is to give it a person's username and password, and it is the wrong one for three reasons that all arrive later rather than sooner: passwords expire and the nightly job stops at 3 a.m.; people leave and their account goes with them; and when something publishes a wrong price, the audit trail names a colleague who was asleep.
An integration token is the alternative. It belongs to a system rather than to a person, it is named after that system, and — issued the way the next section describes — it can be revoked on its own without touching anything else. It is what every OpenEPCIS connector — the UnoPim route, the ERPNext route, the Odoo add-on — authenticates with.
What the token actually is
It is an offline token: an OAuth refresh token issued with the
offline_access scope. The distinction matters, because it is the reason the
thing works at all. An ordinary refresh token dies with the session that
created it, so an integration built on one runs for a few minutes after you set
it up and then stops — a failure mode that looks like a bug in the connector
and is not.
The integration never sends the offline token to the catalog. It trades it at the identity provider for a short-lived access token, and uses that. So the long-lived value sits in one place — the integration's own configuration — and the credential that travels on every request expires in minutes.
Issuing one
Open Profile in DDM and use the integration-tokens card. It takes you through the identity provider's own login and consent screen, and back to a page that shows the token.
Three things about that trip are deliberate and worth knowing before you take it:
You will be asked to consent, even though you are already logged in. That prompt is not a redundancy. An offline token outlives the session that made it, and quite possibly the person who made it, so the person is asked once, explicitly, to allow that.
The token is shown exactly once. Nothing stores it — not DDM, not the resolver. What remains afterwards is the row in your list: the name, when it was issued, when it was last used. If you close the page before copying the value, nothing is broken and nothing is lost except two clicks: issue another one, and revoke the one you abandoned.
Name it after the system, not after yourself. unopim-production and
odoo-nightly are useful names; sven-token-2 is not, because the whole point
of a per-system token is that you can retire one system without wondering what
else you are breaking. You can supply the name when you start the flow, or
rename it afterwards. A flow started without a name stores none — nothing
fails, the row simply comes out unnamed, and naming it later is the remedy.
Issuing a second one: log out first
This is the one step that surprises people, and getting it wrong quietly removes the property the whole mechanism exists for.
A token is bound to a session at the identity provider, not to the click that produced it. Run the flow twice in the same browser without logging out and the second run reuses the session you are already in: you get two different token values that belong to one session. The list then shows a single row, not two — and revoking that row invalidates both tokens at once. One system retired, two integrations down.
So when you need a token per system, end the session between issues: log out, or run the second flow in a private window. Each run then gets its own session, the list shows one row per token, and revoking one leaves the other running.
If you already have two tokens from one session, nothing is broken — they work. They are simply not independently revocable, and the fix is to issue fresh ones with separated sessions and revoke the shared row afterwards.
Putting it into a connector
The token is one property. In the connectors' configuration it is the
target.offline-token of a connection:
openepcis.connectors.connections.pim1.target.offline-token=<the value>
In a cluster the same key arrives as an environment variable — upper-cased,
every non-alphanumeric character turned into _:
OPENEPCIS_CONNECTORS_CONNECTIONS_PIM1_TARGET_OFFLINE_TOKEN
Put it in a Kubernetes secret mounted into the deployment, not in a properties file on disk. See How a connector works for the rest of a connection's configuration.
A token is bound to the realm, the client and the person who issued it. That has a consequence people meet when they build a second environment: a token issued on one environment does not work on another. Copying the value from a staging deployment into production, or the reverse, produces an authentication failure that looks like a typo. Issue one per environment.
Seeing what a token has been doing
The list on the Profile page is metadata only — it never shows a token value again. Each row carries the name, the issue time and the last used time, and that last column is the useful one. A token that has never been used points at an integration that was configured but never started. A token that stopped being used weeks ago points at a system that was retired without anyone revoking its credential, which is exactly the kind of key that should not still be lying around.
You only ever see your own tokens. The list is anchored on the account that issued them, so a colleague's integration tokens are not yours to inspect or revoke — and yours are not theirs.
One row means one session, which is why the section above matters: if two tokens share a session, this list cannot tell them apart, because there is nothing in it that distinguishes them.
Revoking
Revoking deletes the offline session behind the token — and the session is
the unit, which is the second reason to keep one session per token. The
integration's next attempt to trade its token for an access token fails with
invalid_grant, and it will keep failing until someone gives the integration a
new token. That is the
intended behaviour and it is abrupt on purpose: a credential you decided to
withdraw should stop working, not wind down.
So revoke when the system is retired, when a token has been exposed, or when the list shows one nobody can account for. What you should not do is revoke a token to "refresh" it — there is nothing to refresh, and the integration stops until it is reconfigured.
When the card is not there
The feature is off unless a deployment turns it on, and it needs the identity provider's client to be configured for it. If the Profile page shows no integration-tokens card, or the flow answers that it is unavailable, the deployment has not enabled it — that is an administrator's task, not something a retry will fix.
Two failures have a specific cause worth naming:
- "This is not an offline token." The flow refuses to hand over a refresh
token that is not an offline one, rather than giving you a credential that
works for minutes. The client needs the
offline_accessscope allowed. - An expired or unrecognised request. A started flow has to be finished within a short window — ten minutes, by default. Leaving the consent screen open over lunch and then continuing means starting again.