1
1
import NextAuth from 'next-auth' ;
2
2
import { NextAuthOptions } from 'next-auth' ;
3
+ import { JWT } from 'next-auth/jwt' ;
3
4
import CredentialsProvider from 'next-auth/providers/credentials' ;
4
5
6
+ // Helper function to refresh the token
7
+ async function refreshAccessToken ( token : JWT ) {
8
+ try {
9
+ const response = await fetch (
10
+ `${ process . env . NEXT_PUBLIC_API_URL } /api/auth/refresh-token` ,
11
+ {
12
+ method : 'POST' ,
13
+ headers : { 'Content-Type' : 'application/json' } ,
14
+ body : JSON . stringify ( {
15
+ token : token . accessToken ,
16
+ } ) ,
17
+ } ,
18
+ ) ;
19
+
20
+ if ( ! response . ok ) {
21
+ throw new Error ( 'Failed to refresh token' ) ;
22
+ }
23
+
24
+ const refreshedTokens = await response . json ( ) ;
25
+
26
+ // Update permissions from new token if needed
27
+ let permissions = [ ] ;
28
+ if ( refreshedTokens . token ) {
29
+ try {
30
+ const payload = JSON . parse (
31
+ Buffer . from ( refreshedTokens . token . split ( '.' ) [ 1 ] , 'base64' ) . toString ( ) ,
32
+ ) ;
33
+ permissions = payload . permission || [ ] ;
34
+ } catch ( e ) {
35
+ console . error ( 'Error decoding refreshed JWT:' , e ) ;
36
+ }
37
+ }
38
+
39
+ return {
40
+ ...token ,
41
+ accessToken : refreshedTokens . token ,
42
+ expiration : refreshedTokens . expiration ,
43
+ permissions : permissions ,
44
+ roles : refreshedTokens . roles || token . roles , // Keep existing roles if not in response
45
+ } ;
46
+ } catch ( error ) {
47
+ console . error ( 'Error refreshing token:' , error ) ;
48
+
49
+ // Return the original token with an expired flag
50
+ return {
51
+ ...token ,
52
+ error : 'RefreshAccessTokenError' ,
53
+ } ;
54
+ }
55
+ }
56
+
5
57
export const authOptions : NextAuthOptions = {
6
58
providers : [
7
59
CredentialsProvider ( {
@@ -86,9 +138,17 @@ export const authOptions: NextAuthOptions = {
86
138
token . roles = user . roles ;
87
139
token . permissions = user . permissions ;
88
140
token . expiration = user . expiration ;
141
+
142
+ return token ;
89
143
}
90
144
91
- return token ;
145
+ // Return the previous token if the access token has not expired yet
146
+ if ( token . expiration && new Date ( token . expiration ) > new Date ( ) ) {
147
+ return token ;
148
+ }
149
+
150
+ // Access token has expired, try to refresh it
151
+ return refreshAccessToken ( token ) ;
92
152
} ,
93
153
async session ( { session, token } ) {
94
154
if ( token ) {
@@ -104,6 +164,12 @@ export const authOptions: NextAuthOptions = {
104
164
session . permissions = token . permissions ; // Add this line
105
165
// @ts -ignore
106
166
session . expiration = token . expiration ;
167
+
168
+ // Add refresh token error to session if it exists
169
+ if ( token . error ) {
170
+ // @ts -ignore
171
+ session . error = token . error ;
172
+ }
107
173
}
108
174
109
175
return session ;
0 commit comments