Skip to content

Key best practices

The key is the password of your integration. Whoever holds the key does, through the API, everything it allows, on behalf of the member it represents. There is no second factor and no email confirmation. Taking care of the key is taking care of the account.

The server stores only a SHA-256 hash of the key. Not even support can read a key that already exists. It is shown on the creation confirmation screen and never appears again.

The body of the key is 32 bytes drawn from the system’s cryptographic generator. Nobody reaches a key by guessing. The real risk is the key leaking, and that is what this page is about.

Lost the key: rotate it or create another one. There is no recovery.

Store it in your provider’s secret vault, or in an environment variable of the server that makes the calls.

Never store the key:

  • In the code. Not in a versioned config file, not in a “temporary” constant.
  • In a repository, even a private one. Whoever clones takes the key along, and git history keeps what you deleted later.
  • In the browser or in a mobile app. Anyone who opens the page reads the key. The API’s CORS allows only Faturei Hoje’s own screens, so another site’s browser does not even get to read the response.
  • In a URL. The API does not read a key from a query parameter. A URL with a key inside leaks into proxy logs, browser history and the Referer header.
  • In a spreadsheet, a chat or a support ticket. We never ask for your key.

The API accepts the key in one place only, the Authorization header in Bearer format. See Authentication.

The key format is easy to search for: fh_live_, 43 body characters and 6 check characters. A rule matching that shape gets it right almost every time.

You are the one who configures that rule, in your git provider’s secret scanning or in your own pipeline. No provider recognises this format on its own.

Once the enrollment in GitHub’s secret scanning program is active, a key found in a public GitHub repository will be revoked automatically, the webhook endpoints registered with it will be paused (reason emergency_key_rotation, the same as the “Stop now” rotation) and the owner and admins will get an email with the address where it showed up. The enrollment is not active yet: until then, the rule above is still yours to set up.

Create one key for each system that integrates, with a name that says which one it is. Three reasons:

  1. Revoking one does not take the others down. When a key leaks, you replace only that one.
  2. The usage log stays readable. With one key per system, what shows up under View usage is what that system did, not everyone’s calls added together.
  3. The permission stays the right size. Each system gets only what it uses.

The same goes for your own environments. There is no test key and no test environment: fh_test_ is reserved and never issued. If you have production and staging, each one needs its own key, otherwise turning one off turns both off.

Tick only what the integration uses. The panel has shortcuts to start from: Read only, Website form and Full access.

Two limits that come built in:

  • A key never does more than the member it represents. The effective permission is the intersection of the key’s permission with the member’s role and permissions, with the company’s plan on top. It is explained in Permissions.
  • Nobody issues a key above their own role. An ADMIN does not create a key that represents the OWNER.

When the member is suspended, removed or has their access disabled, their key stops answering right away, with 401. That is what makes “turning the person off” also turn off their integrations.

At creation you choose between never expires, 30 days, 90 days or 1 year. After that date the key answers 401 like any invalid key, with no prior warning.

An end date limits the damage of a forgotten key. If you pick one, write the date down next to the reminder to replace it.

Rotating does not renew the term: the new key inherits the date of the old one. See Rotation.

Under the key menu, in View usage, you find the calls of the last 30 days with date, method, path, status, duration, IP and request_id. A refused call also lands there, as long as the API recognised which key it was. The key card also shows the date of the last use and how many IPs are on its list.

What is worth looking for there:

  • a call coming from an IP that is not yours;
  • a run of 401s you were not expecting;
  • recent use on a key you thought was off;
  • a call on a route that integration should not touch.

The OWNER and ADMIN of the company get an email when a key is created, edited, rotated or revoked. An email nobody on the team expected is a signal.

  1. Revoke now. The effect is immediate, there is no undo and no grace period. If you need the integration up, rotate choosing Stop now: that creates the new key and kills the old one in the same action.
  2. Replace the secret in your systems and confirm with a call to GET /public/v1/me.
  3. Read the usage log of the last 30 days looking for a call that was not yours. Keep the request_id of anything that looks odd.
  4. Remove the key from wherever it leaked. Revoking does not erase the copy left in git history, in a log or in a conversation.
  5. If there was misuse, write to dev@fatureihoje.com with what you found. See Report a vulnerability.
  • Allowed IPs: when the address lock helps and when it takes the integration down.
  • Rotation: replacing the secret without breaking anything.
  • Authentication: the key format and the 401 checklist.