GitLab token expired? How to rotate a personal access token in 2026
Short answer
GitLab access tokens expire at midnight UTC on their expiry date, at most 365 days after they're made by default, and GitLab emails you 60, 30 and 7 days before. An expired token can't be reactivated, so create a new one. Before that, rotate it: GitLab revokes the old token at once and gives you a new one with the same scopes. Through the API, pass expires_at, or the new token expires after a week. In the UI, from GitLab 18.1 to 19.5, a rotated personal access token keeps the old expiry date. A token with the api or self_rotate scope can rotate itself.
A CI job, a script or an IDE plugin stops working one morning with a 401: the GitLab token behind it expired. Tokens have to expire, so rotating them before they do is a small, regular job. Here is how expiry works in GitLab in 2026, how to rotate a token in the UI or with the API, and what to do once it’s too late.
When tokens expire
- At midnight UTC on the expiry date, for personal, project and group access tokens alike.
- 365 days at most, by default. New tokens need an expiry date. GitLab’s form suggests 30 days, and a token created through the API without one gets the longest allowed. On GitLab Self-Managed, a feature flag can raise the limit to 400 days, and on Ultimate an administrator can set a shorter maximum.
- No date at all only where it’s allowed: on GitLab Self-Managed or Dedicated, where an administrator turned off Require expiration date, or for service accounts, where a top-level group Owner on GitLab.com or an administrator has allowed it.
See it coming
- Email. A daily check at 1:00 AM UTC warns you 60, 30 and 7 days before a personal access token expires; the 60- and 30-day emails have gone to everyone since GitLab 17.7. For a project access token, the project’s direct Maintainers and Owners get them, and since 17.10 inherited ones can too, where that’s turned on.
- A calendar. Open
/-/user_settings/personal_access_tokens.icson your GitLab while signed in. It redirects to a link with a feed token: add that link to your calendar app for an event on each token’s expiry date. - Who still uses it. On your personal access tokens page, select a token’s name to see when it was last used and its last five IP addresses: the places to update after you rotate.
Rotate a token in GitLab
- In the upper-right corner, select your avatar, then Edit profile.
- In the left sidebar, select Access › Personal access tokens.
- Next to the active token, select the vertical ellipsis (⋮), then Rotate, and Rotate again to confirm.
- Copy the new token before you leave the page, and put it everywhere the old one was.
- The new token has the same scopes and permissions. The old one stops working at once, and GitLab keeps both on record.
- Check the new expiry date. From GitLab 18.1 to 19.5, a personal access token rotated here keeps the old one’s expiry date, so rotating changes the secret but doesn’t buy time. To push the date out, rotate with the API, below, or create a new token. GitLab’s development branch adds an expiry date to the Rotate dialog, so look at what yours shows.
- Project and group access tokens rotate from the project’s or group’s Settings › Access tokens, and there the new token gets the old one’s lifetime again, counted from today.
Rotate it with the API
curl --request POST \
--header "PRIVATE-TOKEN: <your_access_token>" \
--data "expires_at=2027-04-28" \
--url "https://gitlab.example.com/api/v4/personal_access_tokens/<token_id>/rotate"
- GitLab revokes the old token and returns the new one in the response’s
tokenfield, with itsexpires_at. - Without
expires_at, the new token lasts a week on an instance that requires expiry dates, which GitLab does by default. GET /personal_access_tokens?user_id=<your user ID>lists your tokens with their IDs.- Project and group access tokens work the same way:
POST /projects/:id/access_tokens/:token_id/rotateandPOST /groups/:id/access_tokens/:token_id/rotate, with the same one-week default.
Let a token rotate itself
A token with the api or self_rotate scope can rotate itself, which suits a scheduled job that keeps its own token fresh:
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--data "expires_at=2027-01-28" \
--url "https://gitlab.example.com/api/v4/personal_access_tokens/self/rotate"
Project and group access tokens use self in place of the token ID too. Save the new token where the next run will read it.
One token, one rotator. GitLab links each token to the ones rotated from it, and a rotation request made with an already revoked token revokes the whole family. If two jobs share a token and both rotate it, the second one, still holding the old token, cuts off the new one as well.
Once it has expired
Through the API, GitLab answers an expired token with a 401 like this:
{"error":"invalid_token","error_description":"Token is expired. You can either do re-authorization or token refresh."}
A revoked token gets “Token was revoked. You have to re-authorize from the user.” instead. Over HTTPS, Git prints “HTTP Basic: Access denied”, with a note that a token was “either incorrect, expired, or improperly scoped”.
An expired token can’t be reactivated, and it can’t authenticate its own rotation either: /self/rotate answers 401. Create a new token with the same name and scopes (which scopes to pick), then replace the old one in CI/CD variables, Git credential helpers, scripts and apps.
Where legacy tokens are being retired
On a self-managed instance that requires fine-grained personal access tokens, nobody can create or rotate a legacy token after the enforcement date; existing legacy tokens keep working until they expire. Then the replacement has to be a fine-grained token. The enforcement, generally available on GitLab Self-Managed since 19.2, doesn’t cover service accounts, group access tokens or project access tokens.
Tokens in MergeBell
On a self-managed GitLab, MergeBell signs in with a personal access token, and Settings shows its date under Token expires. From a week before, a banner says how many days are left, with New token to open your instance’s token page, name and scope filled in: make a new token, then sign out and sign in with it. If a token runs out or is revoked anyway, the app says “Session expired — sign in again”, and nothing saved on the phone is lost.
The alert server’s read-only key can expire too. When GitLab stops accepting it, Settings › Alerts says alerts need you to sign in again. Until you sign in again, or add a new token on a self-managed GitLab, no alerts are checked, but your alert settings are kept. On gitlab.com, MergeBell signs in on GitLab’s own page, and that sign-in renews itself, with no token to rotate. More in using self-managed GitLab on your phone.
Frequently asked questions
What happens when a GitLab access token expires?
From midnight UTC on its expiry date, GitLab refuses it. The API answers 401 with "Token is expired. You can either do re-authorization or token refresh.", and Git over HTTPS answers "HTTP Basic: Access denied". An expired token can't be reactivated: create a new one and replace the old one wherever it was used.
Can I extend a GitLab token's expiry date?
Not on the same token: GitLab has no way to edit it. Rotate the token through the API with expires_at, up to the maximum lifetime, 365 days by default, or create a new token with a later date.
Why does my rotated GitLab token expire in a week?
The rotate API gives the new token one week when the request has no expires_at and the instance requires expiry dates, as it does by default. Send expires_at=YYYY-MM-DD with the request to choose the date.
Does GitLab warn before a token expires?
Yes. A daily check at 1:00 AM UTC emails you 60, 30 and 7 days before a personal access token expires; for a project access token, the project's direct Maintainers and Owners get the emails. GitLab also has a calendar feed of your tokens' expiry dates: open /-/user_settings/personal_access_tokens.ics while signed in, and add the feed link it redirects you to in your calendar app.
Can a GitLab personal access token never expire?
Not by default: new tokens need an expiry date, 365 days away at most. On GitLab Self-Managed or Dedicated, an administrator can turn off Require expiration date. Service account tokens can be allowed to have none, by a top-level group Owner on GitLab.com or an administrator on GitLab Self-Managed.
Sources
- GitLab docs — Personal access tokens
- GitLab docs — Personal access tokens API: rotate a token
- GitLab docs — Project access tokens
- GitLab docs — Project access tokens API
- GitLab docs — Account and limit settings
- GitLab docs — Fine-grained access tokens
Checked against these pages on 28 October 2026. GitLab changes quickly — if something here no longer matches, tell us and we will fix it.
Do this from your phone with MergeBell
Free for the whole review loop: the To-Do inbox, diffs and line comments, approve and merge, pipelines with retry, and push alerts for your To-Dos. Works with gitlab.com and self-managed GitLab 16.0+.
Get MergeBell for iPhoneGet MergeBell for Android
On the App Store for iOS 26 or later and on Google Play for Android 12 or later. An independent app, not affiliated with GitLab Inc.