In an OAuth 2.0 token response, what does expires_in describe, and how is an access-token lifetime chosen?
answer
- seconds, not a timestamp
- measured from the response, not now
- covers the access token only
- recommended, so it may be absent
- short leak window versus refresh traffic
basics
~20 sexpires_in is the access token's lifetime in seconds, counted from when the response was generated - not an absolute time, and not a statement about the refresh token. The lifetime is chosen to balance how long a leaked token stays useful against how often clients must return to the token endpoint.
solid answer
~50 s`expires_in` is a **relative** value: the number of seconds the access token remains valid, measured from the moment the authorization server generated the response, so `3600` means one hour from then. The client must convert it to an absolute time against its own clock at the moment it receives the response, and should renew a little early rather than waiting for calls to start failing. Two things it does not say: it tells you nothing about the **refresh token**, for which RFC 6749 defines no lifetime member at all, and it is only RECOMMENDED - when it is absent, the server is expected to convey the expiry by other means or document a default rather than the client assuming the token is eternal. Choosing the number is a trade-off between the window in which a leaked access token still works and the traffic every expiry sends back to the token endpoint.
code
pseudocode · 11 lineson token response received:
received_at = local clock now
if response contains expires_in:
expires_at = received_at + expires_in seconds
else:
expires_at = received_at + configured default lifetime
before each call to the resource server:
if local clock now >= expires_at - safety margin:
obtain a new access token with the refresh token
recompute expires_at from the new responsego deeper
Recall that the value is in seconds and that it counts from when the response was produced, not from some fixed date. Know that it refers to the access token.
Explain the conversion a client must perform - receipt time plus seconds, minus a margin - and say why the specification marks the member RECOMMENDED rather than REQUIRED.
Argue the lifetime from a real workload: calls per token, tolerable leak window, and what a token-endpoint outage does to clients whose credentials all expire inside it.
Treat the number as an availability decision as much as a security one. A fleet whose access tokens are shorter than its worst issuer outage has coupled every client's uptime to one service.
## What the member actually says RFC 6749 section 5.1 defines `expires_in` as the lifetime **in seconds** of the access token, and its own example spells out the reading: a value of `3600` means the access token expires one hour from the time the response was generated. Three consequences follow, and each is a place candidates slip: - **It is relative, not absolute.** There is no timestamp in it. The clock it is measured from is the authorization server's, at generation time, and the client only learns of it after network transit. - **It describes the access token only.** RFC 6749 defines no member for the refresh token's lifetime. A client that has been issued a refresh token knows nothing from the response about how long that will be honoured. - **It is RECOMMENDED, not REQUIRED.** When it is omitted, the specification expects the authorization server to provide the expiration time by other means, or to document a default. The client may not read its absence as "this never expires". ## Turning it into something a client can use The client's job is to convert a relative number into an absolute deadline and then renew before it, not on it: 1. record the local time at which the response was **received**; 2. add `expires_in` seconds to get an expiry instant; 3. subtract a safety margin covering transit, processing and clock drift; 4. request a replacement when that earlier instant passes. Using receipt time rather than send time makes the client's estimate conservative, which is the direction you want the error to fall in. Renewing early matters because the alternative - discovering expiry by watching calls fail - turns every lapse into failed work that has to be retried. ## Choosing the number The lifetime is not a style preference; it is where you park the risk of a leak against the cost of renewal. | making it shorter | making it longer | |---|---| | a leaked access token is useful for less time | a leaked access token is useful for longer | | more refresh round trips per client per hour | fewer round trips, less load on the token endpoint | | more traffic concentrated on the authorization server | the authorization server becomes less of a hot path | | a client offline for a while finds its token already dead | a stale token may outlive a change the operator wanted applied | The honest way to reason about it is the ratio: how many API calls does a typical client make per access token? If a lifetime of one hour means one refresh per several hundred calls, the renewal cost is noise. If you cut it to thirty seconds and a client makes two calls in that time, you have built an application that talks to the token endpoint more than to the API it came for. There is a second, quieter reason the number cannot be pushed arbitrarily low: every refresh is a dependency on the authorization server being reachable. An access-token lifetime shorter than the outage you expect to ride out converts a token-endpoint blip into a full outage for every client at once. ## The offline case A berth-holder's phone at a small marina goes out of signal for an afternoon. With a one-hour access token, the credential it carries is dead long before it reconnects, which is exactly the point - that phone has been somewhere hostile, and the credential it was carrying is worthless by the time anyone could have taken it. The application does not treat that as an error; it notices the deadline it computed has passed and obtains a new access token before making its first call. The lifetime choice is what makes that recovery quiet rather than a sign-in screen. ## Where the limit really sits A short lifetime narrows the window in which a stolen access token works. It does not make the token safe to handle carelessly, and it is not a substitute for the grant ever being withdrawn - the token stays valid for its whole life unless the issuer is asked about it, which is a different mechanism. Say what the lifetime buys, which is a bounded window, and no more than that.
- How should a client learn how long its refresh token will last?Not from the token response - RFC 6749 defines no member for it. The client finds out either from the authorization server's documentation or by discovering that a refresh request has stopped being honoured, so it must be written to handle that outcome gracefully rather than assuming the refresh token is permanent.
- Why should a client renew before expiry rather than when a call fails?Because `expires_in` is relative and the client's view of it is already approximate: transit time, processing delay and clock drift all sit between generation and use. Renewing on a margin turns a guaranteed lapse into a scheduled one, and avoids losing in-flight work to failures that then have to be retried.
- What stops an operator from setting the access-token lifetime to a few seconds?Every expiry is a round trip to the token endpoint and a dependency on the authorization server being up. Past a certain point the client spends more traffic renewing than working, and a brief issuer outage becomes an immediate outage for every client, because none of them holds a credential that outlasts it.
saying these in an interview costs you the question
- Reads expires_in as an absolute timestamp rather than seconds
- Thinks expires_in describes how long the refresh token lasts
- Assumes a missing expires_in means the access token never expires
- Believes a very short lifetime removes the need to protect the token
- Waits for calls to fail instead of renewing on a margin
- Treats lifetime as a style choice with no cost either way