Setting JWT lifetime

Hi Team,

I come back to this post because I would like to change the token life time. I saw your explanation and you mentioned that duration can be set on the controller in the yaml setting file. But I don’t see any yaml file on my controller!!! Is it possible? When I used Quickstart, I remember there were yaml files but with our new installation not using Quickstart, I see them nowhere.

Do I have to create such file? And where should it be knowing the tree is /opt/openziti/etc/controller.

Thanks.

[made a toplevel post by clint]
Refer to this other discourse post where JWT lifetime is mentioned:

Hi @Eric, no that's not possible. It's likely you just don't know where it is. If you have a systemd service you can find that location pretty easily with systemctl cat ziti-controller (or whatever the unit is). That should tell you where that config file is.

After you bootstratpped the controller it emits:

INFO: bootstrap completed successfully and will not run again. Adjust /var/lib/private/ziti-controller/config.yml to suit.

That's the file you'd want to change/look at, I believe.

Hi Clint,

I was using "find -iname *,yaml" from root directory and I see with your command that file type is .yml... Sorry, that was a stupid question.

Thanks.

I have looked at the config.yml file and see that life time is set to 180m but when I create an identity, life time is 60m. Is the value in config.yml overwritten by something else?

Hmm. It shouldn't be. You did restart the controller after updating the configuration, correct? If you restarted it, we might need to try to reproduce the behavior. You also indented the yaml properly right? I know that's a 'dumb question' but I mean, I've screwed that up before so I know it's easy to to :slight_smile:

Actually, for now, I’ve done nothing, just read the YAML config file and see this 180m value knowing that tokens life time is 60m in reality. So I believe that this time, it’s not my bad!

Hi,

Here is the setting in config.yml:

/# edgeIdentity - optional
/# A section for identity enrollment specific settings
edgeIdentity:
/# duration - optional, default 180m
/# The length of time that a Ziti Edge Identity enrollment should remain valid. After
/# this duration, the enrollment will expire and no longer be usable.
duration: 180m
/# edgeRouter - Optional
/# A section for edge router enrollment specific settings.
edgeRouter:
/# duration - optional, default 180m
/# The length of time that a Ziti Edge Router enrollment should remain valid. After
/# this duration, the enrollment will expire and no longer be usable.
duration: 180m

Then I have restarted the service:

sudo systemctl restart ziti-controller

Then I have created a new identity at 8:12

Here is the json detail for the token:

"enrollment": {
"ott": {
"expiresAt": "2025-08-26T09:12:08.826Z",
"id": "IyGse5Reqm",
"jwt":

So, duration is 60m instead of 180m. Any idea?

To be entirely honest, I don't know what's going on. You're using the latest ziti?

After I edit my config:

sudo vi /var/lib/private/ziti-controller/config.yml

Set it to 20m (notice there are two to set one for identities and one for routers):

    edgeIdentity:
      # duration - optional, default 180m
      # The length of time that a Ziti Edge Identity enrollment should remain valid. After
      # this duration, the enrollment will expire and no longer be usable.
      duration: 20m
    # edgeRouter - Optional
    # A section for edge router enrollment specific settings.
    edgeRouter:
      # duration - optional, default 180m
      # The length of time that a Ziti Edge Router enrollment should remain valid. After
      # this duration, the enrollment will expire and no longer be usable.
      duration: 180m

then restart the controller and run this block of bash to delete/make an identity and then parse the jwt locally:

ziti edge delete identity 20m
ziti edge create identity 20m -o /tmp/20m.jwt
now=$(date +%s)
expiration=$(cat /tmp/20m.jwt | cut -f2 -d "." | base64 -d 2>/dev/null | jq -r .exp)
echo $now
echo $expiration
echo $((expiration - now))

You'll see in my case, 1200 which is 60*20m in seconds... :frowning: Could you POSSIBLY have another instance of ziti you're connecting to? Or possibly have somehow muffed the edit? :slight_smile:

Examining the codebase, the router logic is utilizing a function intended solely for edge identities. So, a bug. See Router JWTs use Identity expiration configuration value · Issue #3239 · openziti/ziti · GitHub

Hi,

I have changed the settings like this:

edgeIdentity:
  # duration - optional, default 180m
  # The length of time that a Ziti Edge Identity enrollment should remain valid. After
  # this duration, the enrollment will expire and no longer be usable.
  duration: 180m
# edgeRouter - Optional
# A section for edge router enrollment specific settings.
edgeRouter:
  # duration - optional, default 180m
  # The length of time that a Ziti Edge Router enrollment should remain valid. After
  # this duration, the enrollment will expire and no longer be usable.
  duration: 360m

Then I restarted the service and created a new identity but the token life time remains 60 m.

Clint,

I have done what you mentioned:
ziti edge delete identity 20m
ziti edge create identity 20m -o /tmp/20m.jwt
now=$(date +%s)
expiration=$(cat /tmp/20m.jwt | cut -f2 -d "." | base64 -d 2>/dev/null | jq -r .exp)
echo $now
echo $expiration
echo $((expiration - now))

Result is very strange:
delete of identity with id 9OPfDQlepR: OK
New identity 20m created with id: O1Y-NQlWLR
Enrollment expires at 2025-08-29T04:51:19.046Z
1756441879
1756443079
1200

BUT I created it at 06:31 my time and I see this in the json:

"createdAt": "2025-08-29T04:31:19.046Z",
... "enrollment": {
"ott": {
"expiresAt": "2025-08-29T04:51:19.046Z",

my server current time:
Local time: ven. 2025-08-29 06:34:48 CEST
Universal time: ven. 2025-08-29 04:34:48 UTC
RTC time: ven. 2025-08-29 04:34:48
Time zone: Europe/Paris (CEST, +0200)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no

So this means that identity creation is not using local time but UTC time. This explains why I got 60m life time token when duration was set to 3 hours as we are at UTC+2 here.

Am I wrong?

Due to previous test, and because my goal is to obtain a one day life time for the tokens, I have put 26 hours in config.yml (1560m) but when I create new identity, I effectively see a one day life time. :slight_smile:

ziti edge create identity 20m -o /tmp/20m.jwt
now=$(date +%s)
expiration=$(cat /tmp/20m.jwt | cut -f2 -d "." | base64 -d 2>/dev/null | jq -r .exp)
echo $now
echo $expiration
echo $((expiration - now))
Found 0 identities with id or name matching 20m
New identity 20m created with id: 8mTvWNQUt4
Enrollment expires at 2025-08-30T06:44:26.871Z
1756442666
1756536266
93600

Based on your copy/paste it's working properly. The number shown is in seconds not minutes so 1756536266 - 1756442666 = 93600s. 93600s --> 1560m

Soooo, to me it seems like it worked ok... :slight_smile:

:joy: Not exactly!

1560m means 26 hours and I need to put such setting to really get a 24h life time token. Soooo :wink:

I'm confused as to what the problem is then. You can't use 1440 instead of 1560?

If I use 1440, life time will be 22 hours! I guess time is calculated from UTC and we are UTC+2 here.

Can you set it to 1440 and run the commands? I get 86400 -- which is 24h.

Clint,

I think you don't get me, maybe it is due to my poor English usage!

See this:

root@zpix:/# ziti edge delete identity 20m
ziti edge create identity 20m -o /tmp/20m.jwt
now=$(date +%s)
expiration=$(cat /tmp/20m.jwt | cut -f2 -d "." | base64 -d 2>/dev/null | jq -r .exp)
echo $now
echo $expiration
echo $((expiration - now))
Found 0 identities with id or name matching 20m
New identity 20m created with id: h98MqvMlzn
Enrollment expires at 2025-09-02T04:47:34.613Z
1756702054
1756788454
86400
root@zpix:/#

I agree I obtain 84400 seconds BUT look at the expiration time: it's exactly 22 hours after I created it. The problem is that the 24h are starting from UTC time, not my time. Expiration should have been 06:47:34. Does it make sense now?

I take it you are in UTC+2 timezone, right? The first number you show is 1756702054. That corresponds to 2025-09-01 04:47:34Z which is in UTC. i assume you created the identity at 6:47am local time? I should have simply printed that out too. It probably would have made this interaction easy for both of us

Then, the expiration for the token is 24th later at 4:47 UTC the next day.

The ‘Z’ at the end of the date signifies the UTC timezone. Assuming you are in a UTC+2 timezone, it's working correctly. My expectation is that you just aren't familiar with the ‘Z’ timezone?

Actually, when duration was set to 180m, I noticed that life time expired after 1 hour, that's why I linked this behavior to the time zone. Now, after your last explanation, I'm confused on what happened. I'll do additional testing and come back to you.

Thank you.