<!-- 
RSS generated by JIRA (1001.0.0-SNAPSHOT#100246-sha1:7a5c50119eb0633d306e14180817ddef5e80c75d) at Thu Feb 08 23:11:49 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary add field=key&field=summary to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>FOLIO Jira</title>
    <link>https://folio-org.atlassian.net</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>1001.0.0-SNAPSHOT</version>
        <build-number>100246</build-number>
        <build-date>07-02-2024</build-date>
    </build-info>

<item>
            <title>[FOLIO-1233] Implement refresh tokens</title>
                <link>https://folio-org.atlassian.net/browse/FOLIO-1233</link>
                <project id="10290" key="FOLIO">FOLIO</project>
                    <description>&lt;p&gt;While long lived access tokens may be convenient for early development, we really need to implement refresh tokens in FOLIO so our access tokens can be short lived.  We should get to this sooner rather than later. &lt;/p&gt;

&lt;p&gt;As I didn&apos;t see an existing JIRA filed for refresh tokens, this has been created to ensure we keep it visible on our backlog.  We also have some decisions to make regarding refresh token implementation, such as validation, expiration, revocation, and rotation.  There are likely suitable third-party libraries worth considering as well, so we&apos;re not re-inventing the wheel here.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc6749#section-1.5&quot; class=&quot;external-link&quot; rel=&quot;nofollow noreferrer&quot;&gt;https://tools.ietf.org/html/rfc6749#section-1.5&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-oauth-v2-threatmodel-08#section-4.1.2&quot; class=&quot;external-link&quot; rel=&quot;nofollow noreferrer&quot;&gt;https://tools.ietf.org/html/draft-ietf-oauth-v2-threatmodel-08#section-4.1.2&lt;/a&gt;&lt;/p&gt;</description>
                <environment></environment>
        <key id="80659">FOLIO-1233</key>
            <summary>Implement refresh tokens</summary>
                <type id="10002" iconUrl="https://folio-org.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10322?size=medium">New Feature</type>
                            <parent id="80032">FOLIO-3627</parent>
                                    <priority id="10002" iconUrl="https://dev.folio.org/assets/jira-priority/jira-p3.svg">P3</priority>
                        <status id="6" iconUrl="https://folio-org.atlassian.net/images/icons/statuses/closed.png" description="The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.">Closed</status>
                    <statusCategory id="3" key="done" colorName="green"/>
                                    <resolution id="10003">Done</resolution>
                                                        <assignee accountid="62e181430b4bf7ad924b3732">Steve Ellis</assignee>
                                                                <reporter accountid="557058:624212b9-5938-4e3b-84c6-8c8a8db84996">Matthew Jones</reporter>
                                    <labels>
                            <label>refresh-tokens</label>
                    </labels>
                <created>Thu, 26 Apr 2018 20:31:29 +0000</created>
                <updated>Thu, 14 Sep 2023 15:26:47 +0000</updated>
                            <resolved>Mon, 16 May 2022 16:18:34 +0000</resolved>
                                                                        <due></due>
                            <votes>0</votes>
                                    <watches>17</watches>
                                                                <comments>
                                                            <comment id="193281" author="5c38e8d616ac1e4f7cbc660a" created="Wed, 8 Aug 2018 19:46:44 +0000"  >&lt;p&gt;I think one big question to answer here would be how exactly does the refresh token get used? The examples I&apos;ve seen seem to indicate that the client makes use of the refresh token in order to get a new access token when the current one expires, but how much burden does that put on the front end as it currently exists?&lt;/p&gt;</comment>
                                                            <comment id="193285" author="5c38e8d616ac1e4f7cbc660a" created="Tue, 14 Aug 2018 21:04:22 +0000"  >&lt;p&gt;I&apos;m tagging &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5bffed52a1b46046f530c8f7&quot; class=&quot;user-hover&quot; rel=&quot;5bffed52a1b46046f530c8f7&quot; data-account-id=&quot;5bffed52a1b46046f530c8f7&quot; accountid=&quot;5bffed52a1b46046f530c8f7&quot; rel=&quot;noreferrer&quot;&gt;Mike Taylor&lt;/a&gt; and &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5d1cd1e35e43080ce8bf881f&quot; class=&quot;user-hover&quot; rel=&quot;5d1cd1e35e43080ce8bf881f&quot; data-account-id=&quot;5d1cd1e35e43080ce8bf881f&quot; accountid=&quot;5d1cd1e35e43080ce8bf881f&quot; rel=&quot;noreferrer&quot;&gt;Jason Skomorowski&lt;/a&gt; here as I need to get an idea of the impact that implementation of refresh tokens would make on the operations of the front end. If there are others who might be more suited to comment here, please tag them in.&lt;/p&gt;

&lt;p&gt;Here is the run-down of how I envision it working:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;User logs in at standard Folio login endpoint, receives two tokens, an access token and a refresh token. The access token is the same standard token that has always been given, except that it now has a TTL assigned, which is likely quite short (~5 mins or so). The refresh token is also a JWT, but has some metadata in it that makes it more tied to a specific session (e.g., IP restrictions, potentially opaque).&lt;/li&gt;
	&lt;li&gt;The access token is used as before in order to make use of Folio modules. When the TTL expires, the token ceases to work.&lt;/li&gt;
	&lt;li&gt;In order to get a new access token without having to login again, the refresh token is used. There are a number of ways we might think to make this happen, but I think my preference is for an explicit request to get a new access token, something like /token/refresh, where the refresh token is passed and a new access token is minted and returned.&lt;/li&gt;
	&lt;li&gt;By means of this, we can implement a &quot;sliding&quot; session, wherein the user can continually get new access tokens, but these tokens expire quickly and minimize the problem of token leakage.&lt;/li&gt;
	&lt;li&gt;The process of validating a refresh token is significantly more involved than checking an access token, which is stateless. By contrast, an access token contains state, and must be checked against any number of backend requirements, including IP verification or revocation lists.&lt;/li&gt;
	&lt;li&gt;The refresh token would have a significantly longer TTL, such as 24 hours, so re-login wouldn&apos;t be required as long as the user continued to use the same session on the same computer.&lt;/li&gt;
&lt;/ul&gt;
</comment>
                                                            <comment id="193294" author="557058:624212b9-5938-4e3b-84c6-8c8a8db84996" created="Tue, 14 Aug 2018 22:27:18 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5c38e8d616ac1e4f7cbc660a&quot; class=&quot;user-hover&quot; rel=&quot;5c38e8d616ac1e4f7cbc660a&quot; data-account-id=&quot;5c38e8d616ac1e4f7cbc660a&quot; accountid=&quot;5c38e8d616ac1e4f7cbc660a&quot; rel=&quot;noreferrer&quot;&gt;Kurt Nordstrom&lt;/a&gt;, Overall this looks like a good summary.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;my preference is for an explicit request to get a new access token&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Yes. This is how it should be done.&lt;/p&gt;

&lt;p&gt;The UI can manage this orchestration at a low level.  Such logic would exist both prior to and after API requests are made.  For example, if the access token&apos;s expiration is visible, the UI can request a new access token, when expired, prior to issuing an API request for some data.  In the event the UI does receive a 403 from using an expired token, it can request another access token and upon receipt, replay the original API request for data.&lt;/p&gt;

&lt;p&gt;Reporting the TTL as an expiration timestamp may be easier (and more accurate) for UI calculations, rather than having to work back to when the token was issued (which can be troublesome when factoring browser refreshes or network latency).&lt;/p&gt;

&lt;p&gt;5 minutes may be a little short for the access token (things could get very chatty), but certainly it would be measured in minutes, maybe 15, 30, or 60.  As long as its configurable we should be good.  In situations where we need to elevate a user&apos;s scope for a given operation, that token may have a life of only 5 minutes or less. &lt;/p&gt;

&lt;p&gt;The refresh token should be treated like a password and not be persisted anywhere visible on the client.  We should be able to monitor usage and support the ability to invalidate any refresh token that has been issued.  I&apos;ve also seen implementations that issue new refresh tokens with each new access token request, automatically invalidating the prior refresh token effectively making them single-use.&lt;/p&gt;

&lt;p&gt;From a resource perspective, the data requested is an access token, not a refresh token, so IMO the endpoint might simply be /token, but that&apos;s trivial.&lt;/p&gt;</comment>
                                                            <comment id="193300" author="557058:624212b9-5938-4e3b-84c6-8c8a8db84996" created="Tue, 14 Aug 2018 22:34:29 +0000"  >&lt;p&gt;It should also be noted whether we are passing tokens by value or by reference.  I believe we are passing by value today.&lt;/p&gt;</comment>
                                                            <comment id="193305" author="5c38e8d616ac1e4f7cbc660a" created="Wed, 15 Aug 2018 02:00:59 +0000"  >&lt;p&gt;Tokens are currently stateless, so they&apos;re entirely self-contained. I assume that is what we mean by &apos;passing by value&apos;?&lt;/p&gt;

&lt;p&gt;If the refresh token is required to be attached to outgoing requests by the client, how do we keep it from showing up in the traffic logs?&lt;/p&gt;</comment>
                                                            <comment id="193312" author="5bffed52a1b46046f530c8f7" created="Wed, 15 Aug 2018 09:38:56 +0000"  >&lt;p&gt;Thanks for including me in this. Before we get into Stripes details, a couple of points:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5c38e8d616ac1e4f7cbc660a&quot; class=&quot;user-hover&quot; rel=&quot;5c38e8d616ac1e4f7cbc660a&quot; data-account-id=&quot;5c38e8d616ac1e4f7cbc660a&quot; accountid=&quot;5c38e8d616ac1e4f7cbc660a&quot; rel=&quot;noreferrer&quot;&gt;Kurt Nordstrom&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;In order to get a new access token without having to login again, the refresh token is used.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I know I&apos;ve mentioned this before on another thread, but I never got a meaningful answer: how is this better than just logging in again? It&apos;s the same amount of network traffic (one additional call to get the new access token, plus one re-issued call to repeat the application&apos;s request with the new token). And I&apos;m not seeing how it&apos;s any more secure. In either case, if you can spy on the network traffic, you can steal the necessary secret (either user+password pair, or refresh token), so what exactly is this additional step buying us?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=557058%3A624212b9-5938-4e3b-84c6-8c8a8db84996&quot; class=&quot;user-hover&quot; rel=&quot;557058:624212b9-5938-4e3b-84c6-8c8a8db84996&quot; data-account-id=&quot;557058:624212b9-5938-4e3b-84c6-8c8a8db84996&quot; accountid=&quot;557058:624212b9-5938-4e3b-84c6-8c8a8db84996&quot; rel=&quot;noreferrer&quot;&gt;Matthew Jones&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;5 minutes may be a little short for the access token (things could get very chatty)&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I&apos;m not really worried about that. Stripes is already &lt;em&gt;very&lt;/em&gt; chatty. Two more requests every five minutes are not going to make any discernible difference. But as you say, this is going to be configurable anyway (and maybe to different values for different users), so there&apos;s no real problem here.&lt;/p&gt;

&lt;p&gt;Anyway &amp;#8211; on to the impact on Stripes.&lt;/p&gt;

&lt;p&gt;First, it&apos;s obviously a non-starter to require application-level code to deal with this. So it needs to be handled in the network abstraction layer. We presently have two of these: stripes-connect, which is very widely used but in the process of becoming deprecated; and Apollo GraphQL, which is not ready to use outside of inventory, but moving fast and based on standard, well-supported tools.&lt;/p&gt;

&lt;p&gt;We could of course implement all this in stripes-connect, but it strikes me as the kind of code that&apos;s hard to get right, and that tends to harbour lots of edge-cases and mysterious bugs. It would be a pretty major undertaking to do this in a way that we were confident about.&lt;/p&gt;

&lt;p&gt;By contrast, this seems (on the basis of a very cursory search) to be essentially a solved problem for Apollo GraphQL &amp;#8211; in fact, it&apos;s going to be one of those things where the difficulty is not &lt;em&gt;finding&lt;/em&gt; a solution, but _choosing_one. For example:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Sample code for handling this manually: &lt;a href=&quot;https://stackoverflow.com/questions/51262873/how-to-implement-auto-refresh-token-in-graphql-for-jwt-based-authentication&quot; class=&quot;external-link&quot; rel=&quot;nofollow noreferrer&quot;&gt;https://stackoverflow.com/questions/51262873/how-to-implement-auto-refresh-token-in-graphql-for-jwt-based-authentication&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Blog-post exploring the issue and using built-in features of Apollo 2.x: &lt;a href=&quot;https://blog.beeaweso.me/refreshing-token-based-authentication-with-apollo-client-2-0-7d45c20dc703&quot; class=&quot;external-link&quot; rel=&quot;nofollow noreferrer&quot;&gt;https://blog.beeaweso.me/refreshing-token-based-authentication-with-apollo-client-2-0-7d45c20dc703&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;NPM package to do exactly this: &lt;a href=&quot;https://github.com/newsiberian/apollo-link-token-refresh#readme&quot; class=&quot;external-link&quot; rel=&quot;nofollow noreferrer&quot;&gt;https://github.com/newsiberian/apollo-link-token-refresh#readme&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Rather than have all applications use the same refresh-token code in their invocation of Apollo, we would likely create a wrapper library (stripes-apollo) that knows how to do this. We&apos;ve been aware for some time that we&apos;re likely to need such a library, so this would probably be the point to introduce it.&lt;/p&gt;

&lt;p&gt;So my conclusion is that it would be a costly waste of time to implement refresh tokens in stripes-connect, and that the effort it requires would be much better invested in getting our GraphQL implementation up to scratch. (This kind of situation is precisely the reason, or one of them, that Jason pushed for GraphQL for so long.)&lt;/p&gt;

&lt;p&gt;Of course, even if my first point turns out to have some weight, and we choose simply to have the client login again after tokens expire rather than introducing the additional step of a refresh token, it will still be necessary to add session-expiry code to stripes-connect or our use of Apollo, So that conceptual simplification, if we adopted it, would not actually save us much work.&lt;/p&gt;</comment>
                                                            <comment id="193320" author="557058:624212b9-5938-4e3b-84c6-8c8a8db84996" created="Wed, 15 Aug 2018 14:44:54 +0000"  >&lt;blockquote&gt;
&lt;p&gt;how is this better than just logging in again?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;In terms of network traffic, there may not be much difference.  However, the refresh token offers a far better user experience over the user having to repeatedly login We shouldn&apos;t be holding on to the user&apos;s password past the initial login in order to do this automatically.  Further, refresh tokens can be revoked invalidating open sessions (once the last active access token expires) without having to reset the user&apos;s password.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;it&apos;s obviously a non-starter to require application-level code to deal with this&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Agreed and what meant by &quot;orchestration at a low level&quot;.  Thanks for being more specific in your assessment.  I also agree that this effort should largely involve choosing (and configuring) an existing solution.  This sort of problem has been solved many times over.&lt;/p&gt;</comment>
                                                            <comment id="193326" author="5bffed52a1b46046f530c8f7" created="Wed, 15 Aug 2018 15:29:30 +0000"  >&lt;blockquote&gt;&lt;p&gt;The refresh token offers a far better user experience over the user having to repeatedly login.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I didn&apos;t mean the &lt;em&gt;user&lt;/em&gt; logging in again! I meant the software.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;We shouldn&apos;t be holding on to the user&apos;s password past the initial login in order to do this automatically. &lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Why not? (To be clear, I&apos;m not disagreeing with you here, just trying to understand.)&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Refresh tokens can be revoked invalidating open sessions (once the last active access token expires) without having to reset the user&apos;s password.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;OK, that makes sense.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Agreed and what meant by &quot;orchestration at a low level&quot;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I never know what people mean by &quot;orchestration&quot;. And when they start explaining the difference between &quot;orchestration&quot; and &quot;choreography&quot; my frontal lobe shuts down &lt;img class=&quot;emoticon&quot; src=&quot;/images/icons/emoticons/smile.png&quot; height=&quot;16&quot; width=&quot;16&quot; align=&quot;absmiddle&quot; alt=&quot;&quot; border=&quot;0&quot;/&gt;&lt;/p&gt;

&lt;p&gt;Anyway, we seem to be much on the same page,&lt;/p&gt;</comment>
                                                            <comment id="193332" author="5d1cd1e35e43080ce8bf881f" created="Thu, 16 Aug 2018 18:07:48 +0000"  >&lt;p&gt; I think I largely echo Mike&apos;s thoughts on implementation minus the part where we need a &lt;tt&gt;stripes-apollo&lt;/tt&gt; as I think it&apos;s pretty reasonable to do this in &lt;tt&gt;stripes-core&lt;/tt&gt; for now as that&apos;s where we configure the Apollo provider. Abstracting it out would be best planned alongside work to modularise auth.&lt;/p&gt;

&lt;p&gt;I also think we should have the current token available in redux (and via the &quot;stripes context&quot; or whatever we wind up using for accessing global state) so that we continue to afford apps the option of directly making a REST request without intervening abstraction. &lt;/p&gt;

&lt;p&gt;A token with the ability to regenerate a session for 24hrs sounds a bit scary.&lt;/p&gt;</comment>
                                                            <comment id="193338" author="5bffed52a1b46046f530c8f7" created="Fri, 17 Aug 2018 08:14:57 +0000"  >&lt;blockquote&gt;&lt;p&gt;I think I largely echo Mike&apos;s thoughts on implementation minus the part where we need a &lt;tt&gt;stripes-apollo&lt;/tt&gt; as I think it&apos;s pretty reasonable to do this in &lt;tt&gt;stripes-core&lt;/tt&gt; for now as that&apos;s where we configure the Apollo provider.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;If you&apos;re right that we can do all this in the Apollo &lt;em&gt;provider&lt;/em&gt;, then yes &amp;#8211; putting the code in &lt;tt&gt;stripes-core&lt;/tt&gt; is fine. (I&apos;d assumed that we&apos;d need to have refresh-handling code at the point of &lt;em&gt;using&lt;/em&gt; Apollo, which of course will be in many places.)&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;I also think we should have the current token available in redux (and via the &quot;stripes context&quot; or whatever we wind up using for accessing global state) so that we continue to afford apps the option of directly making a REST request without intervening abstraction.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;That seems to me like it&apos;s an unreasonably high bar for client code: there&apos;s a need to handle the possibility of an expired access token, to refresh it, and to retry the operation &lt;em&gt;every&lt;/em&gt; time someone access the WSAPI not via the tools we offer. I mean, sure, let&apos;s not actively prevent that; but it&apos;s hard to imagine anyone will want to ... And much, much, easier to imagine people carelessly doing a one-off &lt;tt&gt;fetch&lt;/tt&gt; without even thinking about any of the token-handling stuff.&lt;/p&gt;</comment>
                                                            <comment id="193345" author="557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d" created="Tue, 21 Aug 2018 07:34:08 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5c38e8d616ac1e4f7cbc660a&quot; class=&quot;user-hover&quot; rel=&quot;5c38e8d616ac1e4f7cbc660a&quot; data-account-id=&quot;5c38e8d616ac1e4f7cbc660a&quot; accountid=&quot;5c38e8d616ac1e4f7cbc660a&quot; rel=&quot;noreferrer&quot;&gt;Kurt Nordstrom&lt;/a&gt; &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5bffed52a1b46046f530c8f7&quot; class=&quot;user-hover&quot; rel=&quot;5bffed52a1b46046f530c8f7&quot; data-account-id=&quot;5bffed52a1b46046f530c8f7&quot; accountid=&quot;5bffed52a1b46046f530c8f7&quot; rel=&quot;noreferrer&quot;&gt;Mike Taylor&lt;/a&gt; I am trying to distill this thread into a short API spec. Corrections welcome.&lt;/p&gt;

&lt;p&gt;Refresh tokens is an approach to avoid long-lived (thus insecure) access tokens. This approach combines the benefit of a stateless (self-verifiable) access token and stateful (revokable) refresh token. The API is as follows:&lt;/p&gt;

&lt;p&gt;1. Client authenticates by calling the &quot;login&quot; endpoint and providing credentials (this rarely happens directly, usually done through users-bl)&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-javascript&quot;&gt;
POST authn/login

{&lt;span class=&quot;code-quote&quot;&gt;&quot;username&quot;&lt;/span&gt;:&lt;span class=&quot;code-quote&quot;&gt;&quot;YYYY&quot;&lt;/span&gt;,&lt;span class=&quot;code-quote&quot;&gt;&quot;password&quot;&lt;/span&gt;:&lt;span class=&quot;code-quote&quot;&gt;&quot;XXXX&quot;&lt;/span&gt;}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the current implementation the response contains the &lt;tt&gt;X-Okapi-Response-Token&lt;/tt&gt; header which is the access token. This needs to change to include both the initial access and refresh token. &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5c38e8d616ac1e4f7cbc660a&quot; class=&quot;user-hover&quot; rel=&quot;5c38e8d616ac1e4f7cbc660a&quot; data-account-id=&quot;5c38e8d616ac1e4f7cbc660a&quot; accountid=&quot;5c38e8d616ac1e4f7cbc660a&quot; rel=&quot;noreferrer&quot;&gt;Kurt Nordstrom&lt;/a&gt; &lt;font color=&quot;red&quot;&gt; the current scheme puts access token in the response header rather than in the body and would require proliferation of headers. I think we should include all token metadata (access, refresh, ttl) in the body. Any problem with this approach?&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;2. Client performs request against FOLIO with the token attached in the request header. When the token expires, FOLIO responds with &lt;tt&gt;401&lt;/tt&gt; and payload indicating the expired token:&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-javascript&quot;&gt;
GET /some/endpoint

401 Unauthorized
{
 &lt;span class=&quot;code-quote&quot;&gt;&quot;message&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;Access token has expired&quot;&lt;/span&gt;,
 &lt;span class=&quot;code-quote&quot;&gt;&quot;code&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;TOKEN_EXPIRED&quot;&lt;/span&gt;,
 &lt;span class=&quot;code-quote&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;auth&quot;&lt;/span&gt;
} 
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This bit here is essential as it allows the client to understand when to refresh the token without tracking TTL. Looks like the popular web APIs use &lt;tt&gt;401&lt;/tt&gt; or &lt;tt&gt;400&lt;/tt&gt; and specific payload to indicate expired tokens. We may also include info about where to refresh the token.&lt;/p&gt;

&lt;p&gt;3. Client refreshes the access token:&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-javascript&quot;&gt;
POST authn/refresh

{&lt;span class=&quot;code-quote&quot;&gt;&quot;refreshToken&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;XYZ&quot;&lt;/span&gt;}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;</comment>
                                                            <comment id="193352" author="557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d" created="Tue, 21 Aug 2018 07:46:12 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=712020%3A38d1a08f-86a8-4df2-9191-239b16b0a81a&quot; class=&quot;user-hover&quot; rel=&quot;712020:38d1a08f-86a8-4df2-9191-239b16b0a81a&quot; data-account-id=&quot;712020:38d1a08f-86a8-4df2-9191-239b16b0a81a&quot; accountid=&quot;712020:38d1a08f-86a8-4df2-9191-239b16b0a81a&quot; rel=&quot;noreferrer&quot;&gt;Heikki Levanto&lt;/a&gt; &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5c38e8d616ac1e4f7cbc660a&quot; class=&quot;user-hover&quot; rel=&quot;5c38e8d616ac1e4f7cbc660a&quot; data-account-id=&quot;5c38e8d616ac1e4f7cbc660a&quot; accountid=&quot;5c38e8d616ac1e4f7cbc660a&quot; rel=&quot;noreferrer&quot;&gt;Kurt Nordstrom&lt;/a&gt; Guys, one more thing I am not clear about is the impact on intermodule communication, for instance when multiple modules are involved in request processing. What will happen when the access token expires while processing a request:&lt;/p&gt;

&lt;p&gt;1. entire request fails with 401&lt;br/&gt;
2. all FOLIO modules need to refresh expired tokens&lt;br/&gt;
3. we have special handling to avoid token expiration while the request is being processed inside OKAPI&lt;/p&gt;

&lt;p&gt;IMHO 1) will not be acceptable, e.g I could imagine a scenerion where the access token is set to a very short TTL (say 1 minute) and the request (comprised of multiple module calls) takes long than that and can never complete. 2) is putting an implementation burden on all modules.&lt;/p&gt;</comment>
                                                            <comment id="193358" author="712020:38d1a08f-86a8-4df2-9191-239b16b0a81a" created="Tue, 21 Aug 2018 08:00:21 +0000"  >&lt;p&gt;We have most of #3 in place already. Mod-authtoken can generate specific tokens for the duration of the request, even specific tokens for each module that participates in the processing. Mostly so that we can handle module-specific permissions (f.ex. mod-login has a permission to create a valid token for users it has authenticated). I don&apos;t remember if we already create a specific token for each request, but it would not be hard to do so. At the same time, we could include the request-id in the token, to make sure that it gets passed on to further requests, and our logs will have the full &quot;stack trace&quot; of the nested requests.&lt;/p&gt;</comment>
                                                            <comment id="193365" author="5c38e8d616ac1e4f7cbc660a" created="Tue, 21 Aug 2018 11:23:31 +0000"  >&lt;p&gt;I don&apos;t know that the access tokens granted to modules based on their module permissions need to be set to short-lived. If these tokens never get exposed to the user, there is no longer the worry that they can be persisted for mischief.&lt;/p&gt;</comment>
                                                            <comment id="193370" author="5c38e8d616ac1e4f7cbc660a" created="Tue, 21 Aug 2018 11:24:14 +0000"  >&lt;blockquote&gt;&lt;p&gt;Kurt Nordstrom the current scheme puts access token in the response header rather than in the body and would require proliferation of headers. I think we should include all token metadata (access, refresh, ttl) in the body. Any problem with this approach?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I don&apos;t think that this should be a problem.&lt;/p&gt;</comment>
                                                            <comment id="193375" author="712020:38d1a08f-86a8-4df2-9191-239b16b0a81a" created="Tue, 21 Aug 2018 12:03:54 +0000"  >&lt;p&gt;As a general principle, we should use short-lived tokens where ever possible. A web service is not likely to run many minutes, because the clients tend to time out at some point. So a 20-minute token should be quite sufficient for inter-module calls. Even a 3-hour token would be acceptable, but I would like to see some kind of expiry time in it, just in case someone manages to sniff network traffic in what is supposed to be our private network, but may not always be so. Cloud service providers have before managed to misconfigure their networks, and admins may leave a SSH session open when they go for lunch...&lt;/p&gt;</comment>
                                                            <comment id="193381" author="5bffed52a1b46046f530c8f7" created="Wed, 22 Aug 2018 14:22:02 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=557058%3Ab8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; class=&quot;user-hover&quot; rel=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; data-account-id=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; accountid=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; rel=&quot;noreferrer&quot;&gt;Jakub Skoczen&lt;/a&gt;&apos;s overview looks good to me. Just two minor comments:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The current scheme puts access token in the response header rather than in the body and would require proliferation of headers. I think we should include all token metadata (access, refresh, ttl) in the body. Any problem with this approach?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I&apos;m not fond of this. At present, &lt;em&gt;every&lt;/em&gt; HTTP response includes an &lt;tt&gt;x-okapi-token&lt;/tt&gt;. I wouldn&apos;t like the token to communicated one way (in the body) in the authentication response, but a different way (in a header) in every other response. So I say just shove the refresh token in an &lt;tt&gt;X-Okapi-Refresh&lt;/tt&gt; header.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Looks like the popular web APIs use 401 or 400 and specific payload to indicate expired tokens. We may also include info about where to refresh the token.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;An alternative is to use code 498 Invalid Token, which is mentioned &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#Unofficial_codes&quot; class=&quot;external-link&quot; rel=&quot;nofollow noreferrer&quot;&gt;on the Wikipedia page&lt;/a&gt; as unofficial, but evidently has some precedent. (I&apos;m not arguing for doing it this way, just noting that it&apos;s an option.)&lt;/p&gt;</comment>
                                                            <comment id="193387" author="5c38e8d616ac1e4f7cbc660a" created="Wed, 22 Aug 2018 15:10:38 +0000"  >&lt;p&gt;I actually like the idea of putting the token in the body as a reply to the login request, since this feels more &quot;explicit&quot; to me. Post credentials, get tokens. Then we continue to use headers for the actual passing of tokens.&lt;/p&gt;</comment>
                                                            <comment id="193397" author="5cf6c546b87c300f36eb7b9a" created="Thu, 26 Sep 2019 15:19:41 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=557058%3Ab8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; class=&quot;user-hover&quot; rel=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; data-account-id=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; accountid=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; rel=&quot;noreferrer&quot;&gt;Jakub Skoczen&lt;/a&gt; &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5c38e8d616ac1e4f7cbc660a&quot; class=&quot;user-hover&quot; rel=&quot;5c38e8d616ac1e4f7cbc660a&quot; data-account-id=&quot;5c38e8d616ac1e4f7cbc660a&quot; accountid=&quot;5c38e8d616ac1e4f7cbc660a&quot; rel=&quot;noreferrer&quot;&gt;Kurt Nordstrom&lt;/a&gt; Where does this stand?  This is currently marked as &quot;in progress&quot; but there haven&apos;t been any updates in a long time...&lt;/p&gt;</comment>
                                                            <comment id="193408" author="5af5e627525ba96b58654f12" created="Wed, 24 Mar 2021 18:41:25 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5cf6c546b87c300f36eb7b9a&quot; class=&quot;user-hover&quot; rel=&quot;5cf6c546b87c300f36eb7b9a&quot; data-account-id=&quot;5cf6c546b87c300f36eb7b9a&quot; accountid=&quot;5cf6c546b87c300f36eb7b9a&quot; rel=&quot;noreferrer&quot;&gt;Craig McNally&lt;/a&gt; This came up in the folio-implementers Slack channel today. Since you&apos;re familiar with the GOBI order API integration, I have a question - if tokens would have to be refreshed on some regular basis, would that affect the GOBI API order creation in FOLIO? Or is that using a different structure to validate and be allowed to make changes in FOLIO?&lt;/p&gt;

&lt;p&gt;cc: &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=557058%3A2f7b6349-450b-419a-ba54-c181f51383ad&quot; class=&quot;user-hover&quot; rel=&quot;557058:2f7b6349-450b-419a-ba54-c181f51383ad&quot; data-account-id=&quot;557058:2f7b6349-450b-419a-ba54-c181f51383ad&quot; accountid=&quot;557058:2f7b6349-450b-419a-ba54-c181f51383ad&quot; rel=&quot;noreferrer&quot;&gt;Dennis Bridges&lt;/a&gt; &lt;/p&gt;</comment>
                                                            <comment id="193411" author="557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d" created="Wed, 10 Nov 2021 13:55:32 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=62e181430b4bf7ad924b3732&quot; class=&quot;user-hover&quot; rel=&quot;62e181430b4bf7ad924b3732&quot; data-account-id=&quot;62e181430b4bf7ad924b3732&quot; accountid=&quot;62e181430b4bf7ad924b3732&quot; rel=&quot;noreferrer&quot;&gt;Steve Ellis&lt;/a&gt; this is a pretty old ticket and we know have more detailed tickets and a spike which also acts as an umbrella for other tickets, would it be okay for me to close this?&lt;/p&gt;</comment>
                                                            <comment id="193422" author="62e181430b4bf7ad924b3732" created="Thu, 11 Nov 2021 13:54:48 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=557058%3Ab8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; class=&quot;user-hover&quot; rel=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; data-account-id=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; accountid=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; rel=&quot;noreferrer&quot;&gt;Jakub Skoczen&lt;/a&gt; Closing this one is fine with me if it improves the organization of the tickets.&lt;/p&gt;</comment>
                                                            <comment id="193431" author="62a96ae7192edb006f9f1bf9" created="Mon, 16 May 2022 15:51:27 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=62e181430b4bf7ad924b3732&quot; class=&quot;user-hover&quot; rel=&quot;62e181430b4bf7ad924b3732&quot; data-account-id=&quot;62e181430b4bf7ad924b3732&quot; accountid=&quot;62e181430b4bf7ad924b3732&quot; rel=&quot;noreferrer&quot;&gt;Steve Ellis&lt;/a&gt; ans &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=557058%3Ab8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; class=&quot;user-hover&quot; rel=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; data-account-id=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; accountid=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; rel=&quot;noreferrer&quot;&gt;Jakub Skoczen&lt;/a&gt; - has implement refresh tokens been implemented. &lt;/p&gt;</comment>
                                                            <comment id="193439" author="62e181430b4bf7ad924b3732" created="Mon, 16 May 2022 16:18:34 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=62a96ae7192edb006f9f1bf9&quot; class=&quot;user-hover&quot; rel=&quot;62a96ae7192edb006f9f1bf9&quot; data-account-id=&quot;62a96ae7192edb006f9f1bf9&quot; accountid=&quot;62a96ae7192edb006f9f1bf9&quot; rel=&quot;noreferrer&quot;&gt;Khalilah Gambrell&lt;/a&gt; I think this ticket can be closed and am closing it. Please feel free to reopen it if it is useful to you. We have more specific tickets which are available if you click on the refresh tokens tag. Where this stands currently: We have implemented and merged most of what is needed in mod-authtoken to support this (
    &lt;span class=&quot;jira-issue-macro resolved&quot; data-jira-key=&quot;MODAT-112&quot; &gt;
                &lt;a href=&quot;https://folio-org.atlassian.net/browse/MODAT-112&quot; class=&quot;jira-issue-macro-key issue-link&quot;  title=&quot;Implement access token expiration and refresh token rotation&quot; &gt;
            &lt;img class=&quot;icon&quot; src=&quot;https://folio-org.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10309?size=medium&quot; /&gt;
            MODAT-112
        &lt;/a&gt;
                                                    &lt;span class=&quot;aui-lozenge aui-lozenge-subtle aui-lozenge-success jira-macro-single-issue-export-pdf&quot;&gt;Closed&lt;/span&gt;
            &lt;/span&gt;
), and we are in progress implementing the changes needed to mod-login (
    &lt;span class=&quot;jira-issue-macro resolved&quot; data-jira-key=&quot;MODLOGIN-186&quot; &gt;
                &lt;a href=&quot;https://folio-org.atlassian.net/browse/MODLOGIN-186&quot; class=&quot;jira-issue-macro-key issue-link&quot;  title=&quot;Implement /login-with-expiry to support token expiration&quot; &gt;
            &lt;img class=&quot;icon&quot; src=&quot;https://folio-org.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10309?size=medium&quot; /&gt;
            MODLOGIN-186
        &lt;/a&gt;
                                                    &lt;span class=&quot;aui-lozenge aui-lozenge-subtle aui-lozenge-success jira-macro-single-issue-export-pdf&quot;&gt;Closed&lt;/span&gt;
            &lt;/span&gt;
) and mod-users-bl (
    &lt;span class=&quot;jira-issue-macro resolved&quot; data-jira-key=&quot;MODUSERBL-150&quot; &gt;
                &lt;a href=&quot;https://folio-org.atlassian.net/browse/MODUSERBL-150&quot; class=&quot;jira-issue-macro-key issue-link&quot;  title=&quot;Implement /login-with-expiry to expose login expiration to the UI&quot; &gt;
            &lt;img class=&quot;icon&quot; src=&quot;https://folio-org.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10309?size=medium&quot; /&gt;
            MODUSERBL-150
        &lt;/a&gt;
                                                    &lt;span class=&quot;aui-lozenge aui-lozenge-subtle aui-lozenge-success jira-macro-single-issue-export-pdf&quot;&gt;Closed&lt;/span&gt;
            &lt;/span&gt;
). &lt;/p&gt;</comment>
                    </comments>
                <issuelinks>
                            <issuelinktype id="10003">
                    <name>Relates</name>
                                            <outwardlinks description="relates to">
                                        <issuelink>
            <issuekey id="74055">MODAT-56</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="10165">UXPROD-39</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="82582">FOLIO-3897</issuekey>
        </issuelink>
                            </outwardlinks>
                                                                <inwardlinks description="relates to">
                                        <issuelink>
            <issuekey id="79617">FOLIO-2524</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="80684">FOLIO-1332</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="80833">FOLIO-1485</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="62056">STCOR-532</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="45404">UIU-1324</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="81655">FOLIO-2556</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="73343">MODLOGSAML-92</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="73345">MODLOGSAML-94</issuekey>
        </issuelink>
                            </inwardlinks>
                                    </issuelinktype>
                    </issuelinks>
                <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_10000" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummarycf">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10057" key="com.atlassian.jira.plugin.system.customfieldtypes:select">
                        <customfieldname>Development Team</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="10144"><![CDATA[Core: Platform]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10014" key="com.pyxis.greenhopper.jira:gh-epic-link">
                        <customfieldname>Epic Link</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue key="$xmlutils.escape($text)">Poppy 2023 R2 - Implement refresh token rotation (RTR) in all affected modules</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            <customfield id="customfield_10019" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>0|hzx3o9:hzzauc</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_10020" key="com.pyxis.greenhopper.jira:gh-sprint">
                        <customfieldname>Sprint</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue id="128">CP: R3 2022 roadmap</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                            <customfield id="customfield_10044" key="com.atlassian.jira.plugin.system.customfieldtypes:float">
                        <customfieldname>Story Points</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>2.0</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                <customfield id="customfield_10024" key="com.atlassian.jira.ext.charting:firstresponsedate">
                        <customfieldname>[CHART] Date of First Response</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>Wed, 8 Aug 2018 19:46:44 +0000</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10025" key="com.atlassian.jira.ext.charting:timeinstatus">
                        <customfieldname>[CHART] Time in Status</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                    </customfields>
    </item>
</channel>
</rss>