Service accounts are available on Pro and Enterprise plans, and only team
Admins can create them.
This page covers Gecko API tokens. The GitLab service account is a
different thing: a user on your GitLab instance whose personal access token
Gecko uses to read code. See
Connect self-managed GitLab.
Personal keys and service account tokens
Both authenticate the v1 API and MCP the same way. They differ in who they act as.
Gecko resolves the role on every request. Change a service account’s role in
Settings > Members and the token’s access changes on its next call.
Create a service account
1
Open the create dialog
Go to Settings > API Keys, click Create API Key, and select
Service account token.
2
Name it after the workload
Use a name that identifies the system that holds the token, such as
gitlab-ci-prod or secops-export. The name appears in the API Keys table
and on the Members page.3
Pick the narrowest role
Read Only is the default. See Choose a role.
4
Set an expiration
Choose 7, 30, 90, or 365 days. Every token expires.
5
Store the token
Gecko shows the token once. Put it straight into your secrets manager;
afterward only a masked preview is shown.
Choose a role
Pick the lowest role that covers every endpoint the workload calls.
The full matrix is in Teams & permissions.
Architecture considerations
Give each workload its own service account
Create one service account per system and environment, such as CI, your developer platform, and your SIEM export, rather than one shared token. Separate accounts give you:- A clear record. Everything a token does is recorded against its service account, so the scans list and finding history show which system acted.
- A separate rate-limit budget. Rate limits apply per key, and a service account has one key, so a noisy export can’t throttle your CI.
- Smaller blast radius. You can revoke one system’s access without touching the others.
- Least privilege. A read-only export never needs the Member role your CI needs to start scans.
The token reads every repository in the team
A service account isn’t filtered by Git host permissions. A token can read findings for every repository connected to the team, whatever its role. That’s what a central pipeline or export needs. It also means the token must never reach individual developers or their tools. Don’t bake it into a developer machine image or a global environment variable, a shared CLI config, an AI coding agent’s skill or plugin, or repository CI variables that every project maintainer can read. Anyone who can read it can list every finding in the team.Let developers and agents scan through your own service
To let developers, or the coding agents they run, scan their own work without Gecko seats or credentials, put a service you own between them and Gecko. Only that service holds the token. Gecko scans code on your Git host, not on the developer’s machine, so work in progress has to be pushed first. A typical flow:1
Push the work
The developer or agent pushes to a branch, such as a short-lived scan
branch, and calls your service with the repository and commit SHA.
2
Authorize the request
Your service authenticates the caller with your existing identity, such as
SSO or their Git host token, and checks on your Git host that they have the
access you require to scan that repository. Reading a repository isn’t
enough on its own: every scan uses your team’s quota, so require write
access, such as having pushed the commit.
3
Reuse or start a scan
To skip a duplicate, look in your own records for a scan your service
already started for the same Git host, repository, and commit whose
status is completed or still running. Don’t search GET /scans for
one: its repository filter matches the path on every connected Git host,
and a scan doesn’t say which host it came from, so a match could belong to
a same-named repository the caller can’t access. Otherwise, including when
your recorded scan failed, was cancelled, or was skipped, call
POST /scans with name, repository, and commit; commit pins the
scan to that exact commit. For GitLab, also send provider: "gitlab" or
pass the full project URL as repository: a bare group/project path is
treated as GitHub.Make the create idempotent, so a lost response doesn’t cost a second scan.
Record a new Idempotency-Key before you call POST /scans, and resend
the same key and the same body on network retries. Once the first request
has finished, Gecko replays its response for 24 hours from the first
attempt. While it’s still running, a retry gets 409 with
idempotency_in_flight: back off and retry with the same key, rather than
giving up on a scan that’s still starting. Use a new key only when you
deliberately start a fresh scan, such as after a failed, cancelled, or
skipped one.4
Wait for it
Poll
GET /scans/{id} until is_done is true. If you subscribe to
webhooks, use them to check sooner, but keep a
slower poll running: an event that fails every delivery attempt is never
resent. Failed and cancelled scans are done
too, so check that status is completed before you read findings, and
treat any other status as a failure rather than a clean result.5
Return only that scan's findings
Read
GET /scans/{id}/vulnerabilities, following next_cursor until
has_more is false, and return those findings to the caller. Record the
scan ID with its Git host, repository, and commit, and against each caller
you served it to, and serve later reads only for scans recorded against
them.PATCH /vulnerabilities/{id} on the caller’s behalf, which needs the
Member role. Gecko only checks the service account’s role, so your service
decides who may triage: allow it only for callers with write access to the
repository, and only for findings from scans recorded against them. For
dismiss and accept_risk, the reason is saved as the finding’s dismissal
reason; for resolve, it’s kept as a note in the finding’s activity history.
Keep your own record of who asked
Gecko records every scan and triage action against the service account, not the person behind your service or pipeline. Log the human or pipeline identity in your system for each call, together with theX-Request-Id header Gecko returns. That lets you trace any
Gecko scan or triage decision back to whoever asked for it.
Plan rotation before the first expiry
Every token expires, and Gecko doesn’t send expiry reminders for API keys. An expired token gets401 with an authentication_error, so a forgotten expiry
shows up as a failing pipeline.
A service account has exactly one token, so you rotate by replacing the
service account:
1
Create the replacement
Create a new service account with the same role, and store its token in your
secrets manager.
2
Roll it out
Deploy the new token to the workload and confirm its calls succeed.
3
Remove the old account
In Settings > Members, choose Remove from Team on the old service
account.
No interactive sign-in
A service account can’t sign in to the dashboard, so SSO and MFA don’t apply to it. The token is the only credential: store it in a secrets manager, inject it at runtime, and never commit it to source control. Send it over HTTPS asAuthorization: Bearer <token> or X-API-Key: <token>.
One team per token
A token is bound to the team it was created in. If you run several Gecko teams, such as one per business unit, create a service account in each.Network egress
API calls go tohttps://app.gecko.security/api/v1. If your workloads
egress through a proxy or TLS inspection layer, allow that host.
Reference patterns
CI pipeline gate
CI pipeline gate
A Member service account per CI system. The pipeline starts a scan
with
POST /scans for the merge request’s branch or commit, polls
GET /scans/{id} until is_done is true, using
webhooks only to check sooner. It fails the job unless
status is completed, then pages through
GET /scans/{id}/vulnerabilities until has_more is false and fails
the job above your severity threshold. So a retried job doesn’t start a
second scan, send an Idempotency-Key on POST /scans that stays the
same across retries, such as one built from the pipeline ID and commit
SHA, with the same request body. A fresh random key on each attempt
starts a new scan. Change the key only when you deliberately rescan
after a failed, cancelled, or skipped scan.Coding agent security review
Coding agent security review
A Member service account held only by an internal service, as in
Let developers and agents scan through your own service.
The agent’s skill pushes its work, asks your service for a scan of that
commit, and gets back only that scan’s findings to fix before it opens a
merge request. Scan once when the work is done rather than on every
commit.
Export to a SIEM or data warehouse
Export to a SIEM or data warehouse
A Read Only service account. Run a scheduled job that pages through
GET /vulnerabilities with cursor pagination, or receive
webhook events and pull full records on
change.Automated GitLab token rotation
Automated GitLab token rotation
When your secrets manager rotates the GitLab service account’s personal
access token, a Manager service account calls
PATCH /integrations/gitlab with the new token. Gecko validates it against
your instance before storing it. Monitor GET /integrations/gitlab for the
token’s expiry date.Revoke access
- Remove the service account with Remove from Team in Settings > Members. The token stops working on its next request and the seat frees up.
- Delete the token in Settings > API Keys. The token stops working immediately, but the service account stays a member and keeps its seat until you remove it.