$ POST /token grant_type=client_credentials scope=reports.read {"token_type":"Bearer","access_token":"eyJhbGciOi...","expires_in":900} ✓ short-lived token issued to the job
Ask a team how many people have access to the finance system and you will get a number within minutes. Ask how many scripts, integrations and scheduled jobs hold credentials to it and the room goes quiet.
Service accounts and API keys are the identities nobody owns: created in a hurry for a project, shared in a chat message, never reviewed, and still working three years after the person who created them left.
They matter because they usually bypass everything you built for humans. There is no second factor on a script. There is often no expiry, no named owner and no alert when one is used from a strange place.
Know what you are dealing with
"Non-human identity" covers several different things, and they need different handling.
| Kind | Example | Typical risk |
|---|---|---|
| Service account | A directory account a batch job signs in with | Shared password, never rotated |
| API key | A long string pasted into an integration | Leaks through code repositories and tickets |
| OAuth client | An app registered to call your APIs | Overly broad scopes |
| Machine token | Short-lived token issued to a workload | Usually fine, if issued per workload |
| Personal token | A developer's own key used by a production job | Breaks when that person leaves |
The last row is the most common and the most damaging. A job that runs under a named employee's credentials stops working on the day that employee is deactivated, or worse, nobody deactivates the person because the job would break.
Watch out
Every service account needs a named owner. Ownerless accounts are the ones that never get rotated.
Step 1: Build an inventory
You cannot manage what you cannot list. Collect from several places, because no single source is complete:
- Your identity platform and directory: accounts flagged as service, or without a person attached.
- Each application's integration or API settings page.
- Secrets in code repositories, CI/CD variables and configuration management.
- Network and gateway logs: which clients call your APIs and how often.
- Finance: recurring invoices for tools that probably have integrations.
For each credential, record these fields in one place:
- Name and purpose, in a sentence.
- Owner: a named person, and a team as backup.
- What it can access, and with which permissions.
- Where the secret is stored.
- Created date, last rotated date, last used date.
- Expiry, if any.
A spreadsheet is a legitimate starting point. A perfect tool you never adopt is worse than a shared sheet you update.
Step 2: Give every identity an owner
An owner is a person who can answer "should this still exist?" Ownership rules that work in practice:
- Every credential has one accountable person, not a mailbox and not a team name alone.
- When that person moves or leaves, ownership transfers as part of the exit process. Add "list credentials owned by this person" to your offboarding checklist.
- Owners confirm their credentials once a quarter. No reply in two reminders means the credential is flagged for suspension.
Step 3: Shrink the permissions
Most service accounts are created with whatever worked first. Review each one and ask: what is the smallest set of operations this job performs?
- A reporting job needs read access to one dataset, not administrator rights.
- An integration that creates users does not need to delete them.
- A credential used by one server should be restricted to that server's network range where your tooling allows it.
If you cannot tell what a credential does, do not delete it immediately. Reduce its rights, enable logging, and see what breaks. A short, announced disruption beats a silent permanent over-grant.
Step 4: Rotate and expire
Static secrets leak. Assume yours will, and limit the damage.
- Prefer short-lived tokens issued to a workload over long-lived keys, wherever the receiving system supports it. The OAuth 2.0 client credentials grant in RFC 6749 exists for exactly this machine-to-machine case.
- Where a long-lived key is unavoidable, set an expiry date and a rotation schedule, for instance every 90 days. Choose a period your team will actually keep.
- Support two valid keys at once during rotation: create the new one, deploy it, confirm use, then revoke the old one.
- Never reuse one key across environments. A leaked test key should not open production.
A rotation runbook, in short:
1. Create new key (name it with the date, e.g. billing-sync-2026-09)
2. Store it in the secrets manager, not in the repo
3. Deploy to the consuming job; confirm a successful call
4. Check "last used" on the old key shows no activity for 24h
5. Revoke the old key; record the date in the inventory
Step 5: Keep secrets out of the usual places
Credentials tend to leak through ordinary habits:
- Pasted into chat or tickets "just for now".
- Committed to a repository, including private ones that later become shared.
- Printed in build logs and error messages.
- Stored in the browser of a person who then shares the screen.
Run a secret scanner on repositories and on CI output. When it finds something, treat the secret as compromised even if the repository was private: rotate first, investigate second.
Step 6: Watch and alert
Non-human identities have predictable behaviour, which makes anomalies easy to spot:
- A key used from a new IP address or country.
- A key used outside its normal hours.
- A sudden jump in call volume or in failures.
- A key used that has had no activity for months.
- Permission changes on a service account.
Send these events to your SIEM. If you are building that pipeline, streaming identity logs to your SIEM covers delivery and the first detections worth writing.
Step 7: Retire what nobody uses
Dormant credentials are free attack surface. Use the last-used date from your inventory:
- Not used for 90 days: notify the owner.
- Not used for 120 days with no response: disable, do not delete.
- Disabled for 30 more days with no complaints: delete, and record it.
Disabling first gives you a quick undo. Deleting is the step you cannot reverse.
A note on what AuthMantra covers
AuthMantra offers a SCIM 2.0 API, SDKs for JavaScript, Python and Android, session visibility, and audit logging with export and streaming, so credential-related events can reach your own monitoring.
Inventory, ownership and rotation policy remain processes you run; AuthMantra does not provide secret vaulting.
What to do this week
- Create the inventory sheet with the six fields above and fill it with the ten credentials you already know about.
- Find every production job running under a named employee's account and list it.
- Assign a named owner to each credential.
- Pick the single most powerful key and rotate it using the runbook.
- Add "transfer or retire owned credentials" to your leaver checklist.