<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Elvin</title>
    <description>The latest articles on Forem by Elvin (@ohmycthulhu).</description>
    <link>https://forem.com/ohmycthulhu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1467126%2F973d67ab-d061-4064-8652-150cc360631f.jpeg</url>
      <title>Forem: Elvin</title>
      <link>https://forem.com/ohmycthulhu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ohmycthulhu"/>
    <language>en</language>
    <item>
      <title>Silent Authentication in Next.js</title>
      <dc:creator>Elvin</dc:creator>
      <pubDate>Thu, 23 Oct 2025 20:00:42 +0000</pubDate>
      <link>https://forem.com/datarockets/silent-authentication-in-nextjs-55kp</link>
      <guid>https://forem.com/datarockets/silent-authentication-in-nextjs-55kp</guid>
      <description>&lt;p&gt;Authentication is an essential part of almost any application and getting it right ensures the security, and improved user experience (UX). In Single Page Applications (SPA), the most common strategy is the JWT-based authentication. It is based on tokens that are used to either authorize actions (&lt;em&gt;access tokens&lt;/em&gt;), or allow reissuing new set of tokens (&lt;em&gt;refresh tokens&lt;/em&gt;).  How we store and use refresh tokens provides fertile ground for security- or UX-related issues. In this article, we discuss a strategy for storing and using refresh tokens in Next.js applications that minimizes security risks while providing the best user experience - Silent Authentication. First, we briefly describe a basic form of JWT authentication and an existing SPA built with Next.js and Ruby on Rails. Then, we introduce Silent Authentication and share how to implement it in your Next.js application. In conclusion, we share user feedback that we received after incorporating Silent Authentication into our production application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Introduction
&lt;/li&gt;
&lt;li&gt;
Basic JWT authentication
&lt;/li&gt;
&lt;li&gt;
Issue with access token expiration
&lt;/li&gt;
&lt;li&gt;
Silent Authentication
&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;Further reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Authentication and authorization are backbone for every major application, and designing it is always a compromise between application's security and user convenience (&lt;em&gt;or user experience, UX&lt;/em&gt;). For example, tightening up the password policy to require very complex passwords will reduce the chances of brute-force attacks, but UX will worsen. Thus, it's important to balance them out, maximizing security while preserving UX.&lt;br&gt;&lt;br&gt;
There are a number of techniques and approaches when it comes to authentication, but in this article, we will focus on token-based strategies for Single Page Application (SPA). In particular, we will be working with Json Web Tokens (JWT), but the methods are applicable to other strategies as well if they match the specification implied in the article. The article assumes the basic understanding of JWT tokens, so if you need to refresh your memory, you may visit &lt;a href="https://www.jwt.io/introduction" rel="noopener noreferrer"&gt;JWT's documentation&lt;/a&gt;.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Basic JWT authentication
&lt;/h2&gt;

&lt;p&gt;Assume that we have a Single Page Application with front-end in &lt;em&gt;Next.js&lt;/em&gt; and back-end in &lt;em&gt;Ruby on Rails&lt;/em&gt;. The authentication on the front-end is built using &lt;a href="https://next-auth.js.org/" rel="noopener noreferrer"&gt;&lt;em&gt;NextAuth.js&lt;/em&gt;&lt;/a&gt;. The system already supports a basic JWT authentication, i.e. back-end can issue an access token given credentials and can authorize an action when an access token is provided.&lt;br&gt;
In Next.js, the application consists of two parts that are run in different environments. The server-side (later, &lt;em&gt;server-side application&lt;/em&gt;) runs on the front-end server and its code and data are hidden from user. Another part is client-side (later, &lt;em&gt;client-side application&lt;/em&gt;) is run inside the browser. Thus, all code and data are inherently exposed to users.&lt;br&gt;
The authentication works as follows: the server-side application is responsible for obtaining and storing access tokens. So, when a user signs in, NextAuth.js sends a request to the back-end, obtains an access token, stores it, and provides it to the client-side application. The flow can be seen in the diagram below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjmyss0hd0x958ah27et.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjmyss0hd0x958ah27et.png" alt="Authentication Flow" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, the client-side application obtains an access token from the server-side application (&lt;a href="https://next-auth.js.org/getting-started/client#usesession" rel="noopener noreferrer"&gt;using NextAuth session&lt;/a&gt;), and uses it when it makes requests to the back-end  application. This way, the access token is available for usage in the client-side, but access to it is controlled by the server-side code. The diagram below describes loading the application and performing an action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc09viupawyben6ldolay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc09viupawyben6ldolay.png" alt="Interaction within the application" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Issue with access token expiration
&lt;/h2&gt;

&lt;p&gt;Even though the described approach is quite secure, it has a major UX issue: access tokens expire, and they expire quite fast. It leads to interruptions in user experience, since the expiration might happen mid-action, and the user will be required to reauthenticate before continuing their action. To mitigate this, we need to introduce a mechanism for reauthenticating user without any interaction from their side - Silent Authentication. Silent Authentication should work "under the hood" to ensure that a user has a valid access token when they need it. &lt;br&gt;
The strategies for Silent Authentication can be categorized into two groups:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;refreshing an access token if it's close to being invalid;
&lt;/li&gt;
&lt;li&gt;using a separate token for issuing a new access token - refresh tokens.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The former solution is simpler to implement, but it has two major flaws: a short window for refreshing the token (making it useless for cases when a user pauses the interaction for some time), and increasing the importance of access tokens. Since access tokens are exposed to browsers, they can be accessed by a user and are susceptible to Man-In-The-Middle attacks. So, if an attacker obtains an access tokens and access tokens might be exchanged for new tokens, then they can keep using the system indefinitely by making sure that the access tokens never expire.&lt;/p&gt;

&lt;p&gt;The more robust and secure approach is introducing a separate token that will be used only for issuing new access tokens - refresh tokens. Refresh tokens are much more long lived (e.g., several months for refresh tokens vs several hours for access tokens), which allows users to avoid reauthentication even if they haven't visited the system for a long time. The implementation of reauthentication is error-prone, and measures should be taken to reduce the attack surface.&lt;/p&gt;

&lt;p&gt;There are several precautionary measures that can be taken to improve security:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hiding refresh token from the user - as gaining refresh tokens provides a way to continuously generate access tokens, thus keeping access to the system on behalf of a user, we need to avoid exposing it;&lt;/li&gt;
&lt;li&gt;refresh token rotation - refresh tokens should be one-time use only, and using one refresh token should generate another one;&lt;/li&gt;
&lt;li&gt;guardrails for reusing refresh tokens - if a refresh token is trying to be reused, it might be a sign of a malicious actor reusing the refresh token. An optional precaution will be to invalidate refresh and access tokens for the user, forcing all actors on behalf of the said user to reauthenticate. &lt;em&gt;This should be used cautiously to avoid allowing an actor to continuously reuse an expired refresh token to force a user to authenticate.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Silent Authentication
&lt;/h2&gt;

&lt;p&gt;In this article, we focus on implementing Silent Authentication using Next.js with a technology-agnostic back-end, and excluding the logic related to refresh tokens on the back-end.  For the back-end, we assume that all measures described in the previous section were implemented.&lt;/p&gt;

&lt;p&gt;Given that we have a system with basic JWT authentication and back-end that supports refresh tokens functionality, we want to introduce Silent Authentication. We have two areas to cover: storing refresh tokens and using refresh tokens. In our setup, storing refresh tokens is the easiest problem to solve - NextAuth.js encapsulates the authentication-related logic within the server-side application, allowing us to control what data the client-side application has access to that is controlled using &lt;a href="https://next-auth.js.org/configuration/callbacks" rel="noopener noreferrer"&gt;callbacks&lt;/a&gt;. Generally, callbacks contain logic for authentication, exposing session data (note: session within the front-end, not with the back-end ), and providing granular control on which data is exposed to the client. Thus, all we need to do is to store the refresh token on authentication (in &lt;code&gt;jwt&lt;/code&gt; callback) and avoid exposing it when the client application requests session information (in &lt;code&gt;session&lt;/code&gt; callback):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;authenticateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="c1"&gt;// `authenticateUser` handles sign-in request to the backend, it returns an object with the following fields:  &lt;/span&gt;
    &lt;span class="c1"&gt;// - `token` - access token&lt;/span&gt;
    &lt;span class="c1"&gt;// - `refresh_token` - refresh token&lt;/span&gt;
    &lt;span class="c1"&gt;// - `expires_at` - access token expiration datetime  &lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;    
        &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refreshToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refresh_token&lt;/span&gt;    
        &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expires_at&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;  
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// token consists of `token` as access token, and `expiresAt` as expiration datetime  &lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;    
      &lt;span class="c1"&gt;// Expiration datetime will be needed on the client to determine when to request reauthentication  &lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
      &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresAt&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Avoid exposing refresh token via `session`  &lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a result, we avoid exposing refresh tokens to the client-side application altogether while allowing the server-side application to perform reauthentication using refresh tokens.&lt;/p&gt;

&lt;p&gt;And the next step is to avoid having expired access tokens when the front-end needs it. There are two ways to achieve it:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep the access token always valid while the user uses the front-end;&lt;/li&gt;
&lt;li&gt;refresh the access token before the action if it's invalid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We decided to go with the former approach as it is simpler to implement and helps with some concurrency-related issues (e.g., performing an action that requires several parallel requests). It comes with a cost of redundant token refreshes that will be relevant for when the user doesn't perform any actions for a long period.&lt;/p&gt;

&lt;p&gt;The implementation is pretty straightforward. In &lt;code&gt;jwt&lt;/code&gt; callback, reauthenticate if the access token is invalid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;  
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refreshToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refreshToken&lt;/span&gt;  
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expiresAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresAt&lt;/span&gt;  
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expiresAt&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;expiresAt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;  
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expired&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="nx"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;rotateTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, every time the client requests the access token, it will be valid. And to keep the access token valid, we need to request it as soon as it expires - we can do it using a custom hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useRefreshSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authenticated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expiresAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expiresAt&lt;/span&gt;  
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;expiresAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// dayjs library is used for working with datetime        const timeLeft = dayjs(expiresAt).diff(dayjs())&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeLeft&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;timeLeft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This hook should be called on the top level within the necessary &lt;a href="https://next-auth.js.org/getting-started/client#sessionprovider" rel="noopener noreferrer"&gt;&lt;code&gt;SessionProvider&lt;/code&gt;&lt;/a&gt; (e.g., in a top component declared in &lt;code&gt;_app.tsx&lt;/code&gt; ). &lt;/p&gt;

&lt;p&gt;As a result, we receive a system that is described in the diagram below:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6ofwbk0af15wbxmvsn9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6ofwbk0af15wbxmvsn9.png" alt="Interaction within the application" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;After introducing Silent Authentication, we received a lot of positive feedback from satisfied users - users were happy that they don't have to reauthenticate constantly, especially when coming back to the system after a week or two. And, what's also very important, we managed to avoid big security risks by never transferring refresh tokens to the client. This is how we achieved a secure but convenient authentication mechanism in our system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://auth0.com/docs/secure/application-credentials" rel="noopener noreferrer"&gt;Auth0 articles on authentication&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://auth0.com/docs/authenticate/protocols/oauth" rel="noopener noreferrer"&gt;OAuth protocol&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://next-auth.js.org/" rel="noopener noreferrer"&gt;NextAuth.js documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@iason.tzortzis/cookie-security-best-practices-d19800ad0b4b" rel="noopener noreferrer"&gt;Best practices on secure cookies&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://blog.dreamfactory.com/implementing-oauth-2.0-in-rest-apis-complete-guide" rel="noopener noreferrer"&gt;Example of building a system with JWT-based OAuth authentication&lt;/a&gt;; &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>security</category>
      <category>react</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
