Skip to content

API tokens with expiration date#23859

Merged
MarkEWaite merged 14 commits intojenkinsci:masterfrom
mawinter69:expiring-tokens
Jan 26, 2026
Merged

API tokens with expiration date#23859
MarkEWaite merged 14 commits intojenkinsci:masterfrom
mawinter69:expiring-tokens

Conversation

@mawinter69
Copy link
Contributor

@mawinter69 mawinter69 commented Nov 25, 2025

API tokens can now get an optional expiration date. Added a select drop down from where you can choose from predefined durations (default is 30 days), a custom date (max 1 year in the selector from the date input field) and no expiration. Expiration date is shown in the list. Not expiring tokens and tokens that expire in less than 7 days are marked with warning, expired tokens are marked with error.
The sidepanel on the user page now has a badge for the security action when there are tokens that expired or are about to expire. In the header the user avatar has a badge and in the dropdown is a badge.

Fixes #16695
image

image image

Testing done

Interactive testing for the UI part
Added tests for the scripting part, ensuring that expired tokens are not accepted

Proposed changelog entries

  • API tokens with expiration date

Proposed changelog category

/label rfe

Proposed upgrade guidelines

N/A

Submitter checklist

  • [ ´x] The issue, if it exists, is well-described.
  • [ ]xThe changelog entries and upgrade guidelines are appropriate for the audience affected by the change (users or developers, depending on the change) and are in the imperative mood (see examples). Fill in the Proposed upgrade guidelines section only if there are breaking changes or changes that may require extra steps from users during upgrade.
  • There is automated testing or an explanation as to why this change has no tests.
  • New public classes, fields, and methods are annotated with @Restricted or have @since TODO Javadocs, as appropriate.
  • New deprecations are annotated with @Deprecated(since = "TODO") or @Deprecated(forRemoval = true, since = "TODO"), if applicable.
  • UI changes do not introduce regressions when enforcing the current default rules of Content Security Policy Plugin. In particular, new or substantially changed JavaScript is not defined inline and does not call eval to ease future introduction of Content Security Policy (CSP) directives (see documentation).
  • For dependency updates, there are links to external changelogs and, if possible, full differentials.
  • For new APIs and extension points, there is a link to at least one consumer.

Desired reviewers

@mention

Before the changes are marked as ready-for-merge:

Maintainer checklist

  • There are at least two (2) approvals for the pull request and no outstanding requests for change.
  • Conversations in the pull request are over, or it is explicit that a reviewer is not blocking the change.
  • Changelog entries in the pull request title and/or Proposed changelog entries are accurate, human-readable, and in the imperative mood.
  • Proper changelog labels are set so that the changelog can be generated automatically.
  • If the change needs additional upgrade steps from users, the upgrade-guide-needed label is set and there is a Proposed upgrade guidelines section in the pull request title (see example).
  • If it would make sense to backport the change to LTS, be a Bug or Improvement, and either the issue or pull request must be labeled as lts-candidate to be considered.

API tokens can now get an optional expiration date.
Added a select drop down from where you can choose from predefined
durations, a custom date (max 1 year) and no expiration.
Expiration date is shown in the list. Not expiring tokens are marked
with warning.

fixes jenkinsci#16695
@comment-ops-bot comment-ops-bot bot added the rfe For changelog: Minor enhancement. use `major-rfe` for changes to be highlighted label Nov 25, 2025
@mawinter69 mawinter69 changed the title API tokens with expiration API tokens with expiration date Nov 25, 2025
@mawinter69
Copy link
Contributor Author

The SetupWizard allows to generate an API Token. Should that be automatically an expiring token maybe?

@timja
Copy link
Member

timja commented Nov 26, 2025

The SetupWizard allows to generate an API Token. Should that be automatically an expiring token maybe?

how do you generate one in the setup wizard?

@lemeurherve
Copy link
Member

lemeurherve commented Nov 26, 2025

Would it be possible/desirable to have even shorter periods like 1 hour? I'm thinking about tokens that could be used for short-lived jobs.

this.isLegacy = token.isLegacy();
LocalDate expirationDate = token.getExpirationDate();
if (expirationDate == null) {
this.expirationDate = "never";
Copy link
Member

@lemeurherve lemeurherve Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be a breaking change maybe for later, but how about having a short-lived token generated by default instead of an eternal one to prevent mistakes, and to ensure eternal token creation is a conscencious and deliberate choice?

(EDIT: The line I put this comment on isn't the proper one, sorry)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the UI the default is set to 30 days.

@novinxy
Copy link

novinxy commented Nov 26, 2025

What is default expiration ? Is it "never" or some sane time like 1 month ?
What happens near expiration ? Is there some notification(on UI or mail) before , e.g. week before? It would be shame to expire without notificating user in advance

@mawinter69
Copy link
Contributor Author

The SetupWizard allows to generate an API Token. Should that be automatically an expiring token maybe?

how do you generate one in the setup wizard?

You can set a system property then it generates an api token or uses a given one. See

@mawinter69
Copy link
Contributor Author

Would it be possible/desirable to have even shorter periods like 1 hour? I'm thinking about tokens that could be used for short-lived jobs.

Technically possible, though not sure how much sense this makes. How do you get to this token? You would need to use your password in some way or another token. And by default I think even the SYSTEM account is not able to generate new token for a user.
What would be a nice feature but that would require major refactoring is to have tokens with reduced permissions. E.g. you have build permissions for a user but want to create a token that has only read permissions and not build.

@mawinter69 mawinter69 marked this pull request as draft November 26, 2025 18:38
@mawinter69
Copy link
Contributor Author

What is default expiration ? Is it "never" or some sane time like 1 month ? What happens near expiration ? Is there some notification(on UI or mail) before , e.g. week before? It would be shame to expire without notificating user in advance

In the UI I set the default to 30 days. Notifications make sense. Maybe I can add some badge to the user icon in the header to inform about expiring tokens.
Sending mail notification is not possible out of the box as there is no support for mail sending in core. You need at least the mailer plugin

@timja
Copy link
Member

timja commented Nov 26, 2025

Sending mail notification is not possible out of the box as there is no support for mail sending in core. You need at least the mailer plugin

Could be an extension point but probably not worth it? Those emails just annoy me I've intentionally set it short for a one-off / temporary thing don't bug me about it

@mawinter69
Copy link
Contributor Author

Sending mail notification is not possible out of the box as there is no support for mail sending in core. You need at least the mailer plugin

Could be an extension point but probably not worth it? Those emails just annoy me I've intentionally set it short for a one-off / temporary thing don't bug me about it

When you have tokens that run for several month some kind of notification besides an icon might be useful. I see the main purpose of the expiring tokens when a user wants to do some experiments. For automation purposes I would anyway assume that those are usually technical users where an email address might not be available and where hardly anyone logs on in the UI in Jenkins. So they will probably stick to not expiring tokens.

@mawinter69
Copy link
Contributor Author

Should expired tokens be automatically removed? Instantly, after a week, configurable or never?

@mawinter69 mawinter69 marked this pull request as ready for review November 29, 2025 21:05
@timja
Copy link
Member

timja commented Nov 29, 2025

Should expired tokens be automatically removed? Instantly, after a week, configurable or never?

I would leave them, most systems I can think of leave them around.

@daniel-beck daniel-beck self-requested a review December 3, 2025 21:20
@timja
Copy link
Member

timja commented Jan 22, 2026

The balance of this feels a bit off:
image

Adding a third line really throws off alignment, especially with the buttons being on the middle line.
Do we need the created date at all? Isn't last used more important?


Date format is inconsistent:

image image

Date picker appears to use a locale based format, where-as the two places the date is shown are using YYYY-MM-DD.
Ideally it would display in a locale specific format, I think there's a tag for that, i:formatDate?


Apart from above looks great.

@janfaracik janfaracik self-requested a review January 23, 2026 11:37
@mawinter69
Copy link
Contributor Author

Date picker appears to use a locale based format, where-as the two places the date is shown are using YYYY-MM-DD. Ideally it would display in a locale specific format, I think there's a tag for that, i:formatDate?

the date picker is the browser-built-in. So I'm not able to change that. i:formatDate (which I can't use as it only works with Date but I use LocalDate) and also the DateTimeFormatter with style short produces strings with 2 digit years and without leading zeros for english locale, e.g. 2/23/26 so this is also not 100% in sync.
I could also incorporate flatpickr to get a better styled date picker. It's vanilla js, works fine and added it in plugins already though it is not that well maintained (last commit 4 years ago).

@mawinter69
Copy link
Contributor Author

How about this:
image

That removes the creation string. Adding the creation timestamp as a tooltip to the span with the expiration

@timja
Copy link
Member

timja commented Jan 23, 2026

That looks better

@timja
Copy link
Member

timja commented Jan 23, 2026

Date picker appears to use a locale based format, where-as the two places the date is shown are using YYYY-MM-DD. Ideally it would display in a locale specific format, I think there's a tag for that, i:formatDate?

the date picker is the browser-built-in. So I'm not able to change that. i:formatDate (which I can't use as it only works with Date but I use LocalDate) and also the DateTimeFormatter with style short produces strings with 2 digit years and without leading zeros for english locale, e.g. 2/23/26 so this is also not 100% in sync. I could also incorporate flatpickr to get a better styled date picker. It's vanilla js, works fine and added it in plugins already though it is not that well maintained (last commit 4 years ago).

Can you convert from LocalDate to date then use it?
That format looks better than what's there now.

@mawinter69
Copy link
Contributor Author

I actually do the locale formatting already in Java now. And working with the Date class is not really nice.

make the creation date a tooltip of the expiration
@mawinter69
Copy link
Contributor Author

Do we need some kind of admin monitor for tokens that are about to expire or have expired? That might be useful when api tokens with expiration date are set for technical users, where usually nobody logs in via the UI.

@timja
Copy link
Member

timja commented Jan 23, 2026

Do we need some kind of admin monitor for tokens that are about to expire or have expired? That might be useful when api tokens with expiration date are set for technical users, where usually nobody logs in via the UI.

I don’t think so. Not for user tokens.

some systems have the concept of system or resource owner tokens where ownership isn’t by an individual so that when someone leaves they don’t break and it might make sense there but I don’t think it makes sense at an individual level. Maybe there could be a page listing API tokens and their statuses.

An admin monitor shouldn’t be for a normal everyday activity though of expiring tokens

@janfaracik
Copy link
Member

Looking great - couple points:

  • Dialog width changes when you change to a custom expiration date
  • The expiration date looks good, might work better in a slightly smaller font, e.g. var(--font-size-xs) and maybe a secondary text colour for distant dates

@mawinter69
Copy link
Contributor Author

  • made the dialog larger so it should not change width
  • reduced font size for expiration
image

dateInput.min = now.toISOString().split("T")[0];
dateInput.max = nextYear.toISOString().split("T")[0];
dateInput.value = presetDate.toISOString().split("T")[0];
form.appendChild(formTemplate);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if worth fixing, but when a new api token is added to the list it is always added to the bottom.

but when you refresh the page the tokens are sorted alphabetically.
Bit strange that they jump around

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That hasn't changed. It was like that before.

<option value="never">No Expiration</option>
</select>
</div>
<input type="date" name="tokenExpiration" class="jenkins-hidden jenkins-input token-expiration-date"/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should have a min set to today and it should be validated server side that the expiry is not in the past.

Convenient for testing but I don't think it should be allowed.

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I programmatically set min and max in javascript. Which is properly applied in the picker but that doesn't prevent you from manually changing the date to something in the past directly in the input field.
I can add validation in java

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a validation on server side. When in the past the token is not added and an alert is shown
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly in Chrome when you select the year and then use the arrow up/down buttons, it respects the limits from minand max. Firefox does not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only respects the year weirdly with up and down buttons. I tested by adjusting the month to later in the year and I can adjust day and month into the past and just type a date in the past too.

Good enough I guess, unless we want to add client side validation too

Copy link
Member

@timja timja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall it LGTM.

I added a few nits that would be good to improve, but they aren't blockers to me.

don't add token when choosing date in the past

directly warn after creation when about to expire
Copy link
Member

@janfaracik janfaracik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes :) LGTM.

Copy link
Member

@timja timja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-tested, changes looks good


/label ready-for-merge


This PR is now ready for merge, after ~24 hours, we will merge it if there's no negative feedback.

Thanks!

@comment-ops-bot comment-ops-bot bot added the ready-for-merge The PR is ready to go, and it will be merged soon if there is no negative feedback label Jan 24, 2026
@MarkEWaite MarkEWaite merged commit 5490f91 into jenkinsci:master Jan 26, 2026
18 checks passed
meetgoti07 pushed a commit to meetgoti07/jenkins that referenced this pull request Jan 29, 2026
* API tokens with expiration

API tokens can now get an optional expiration date.
Added a select drop down from where you can choose from predefined
durations, a custom date (max 1 year) and no expiration.
Expiration date is shown in the list. Not expiring tokens are marked
with warning.

fixes jenkinsci#16695

* revert changes in SetupWizard

* fix linter

* fix ordering

* show when token expired

* notify on expiring and expired tokens

* format

* 2 lines only

make the creation date a tooltip of the expiration

* feedback

* feedback 2

don't add token when choosing date in the past

directly warn after creation when about to expire

* prettier

---------

Co-authored-by: Tim Jacomb <timjacomb1@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-merge The PR is ready to go, and it will be merged soon if there is no negative feedback rfe For changelog: Minor enhancement. use `major-rfe` for changes to be highlighted

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JENKINS-75492] Allow to give api tokens an expiration date

6 participants