1
1
import NextAuth from 'next-auth'
2
+ import axios from 'axios'
3
+ // TODO(alishaevn): use the api value from https://github.com/assaydepot/rx/issues/21497 in the next phase
4
+ import { EXPIRATION_DURATION } from '../../../utils'
2
5
3
6
// For more information on each option (and a full list of options) go to: https://next-auth.js.org/configuration/options
4
7
const authOptions = {
@@ -28,11 +31,22 @@ const authOptions = {
28
31
callbacks : {
29
32
async jwt ( { token, account, user } ) {
30
33
// Triggered on the initial sign in
31
- // TODO(alishaevn): account for the refresh token
32
34
if ( account && user ) {
33
- token . accessToken = account . access_token
35
+ return {
36
+ accessToken : account . access_token ,
37
+ accessTokenExpires : Date . now ( ) + EXPIRATION_DURATION ,
38
+ refreshToken : account . refresh_token ,
39
+ user,
40
+ }
41
+ }
42
+
43
+ // Return previous token if the access token has not expired yet
44
+ if ( token . accessTokenExpires && ( Date . now ( ) < token . accessTokenExpires ) ) {
45
+ return token
34
46
}
35
- return token
47
+
48
+ // Access token has expired, try to update it
49
+ return refreshAccessToken ( token )
36
50
} ,
37
51
async session ( { session, token } ) {
38
52
// Send additional properties to the client
@@ -42,4 +56,42 @@ const authOptions = {
42
56
}
43
57
}
44
58
59
+ /**
60
+ * Takes a token, and returns a new token with an updated `accessToken`.
61
+ * If an error occurs, returns the old token and an error property
62
+ */
63
+ const refreshAccessToken = async ( token ) => {
64
+ try {
65
+ const url = `https://${ process . env . NEXT_PUBLIC_PROVIDER_NAME } .scientist.com/oauth/token`
66
+ const encodedString = Buffer . from ( `${ process . env . CLIENT_ID } :${ process . env . CLIENT_SECRET } ` ) . toString ( 'base64' )
67
+ const params = new URLSearchParams ( {
68
+ grant_type : 'refresh_token' ,
69
+ refresh_token : token . refreshToken ,
70
+ } )
71
+
72
+ const response = await axios . post ( url , params , {
73
+ headers : {
74
+ 'Authorization' : `Basic ${ encodedString } ` ,
75
+ } ,
76
+ } )
77
+ const refreshedTokens = response . data
78
+
79
+ if ( response . status !== 200 ) {
80
+ throw refreshedTokens
81
+ }
82
+
83
+ return {
84
+ ...token ,
85
+ accessToken : refreshedTokens . access_token ,
86
+ accessTokenExpires : Date . now ( ) + EXPIRATION_DURATION ,
87
+ refreshToken : refreshedTokens . refresh_token ?? token . refreshToken , // Fall back to the old refresh token
88
+ }
89
+ } catch ( error ) {
90
+ return {
91
+ ...token ,
92
+ error : 'RefreshAccessTokenError' ,
93
+ }
94
+ }
95
+ }
96
+
45
97
export default NextAuth ( authOptions )
0 commit comments