Skip to content

Commit d8a35f0

Browse files
authored
Merge pull request #1 from thomasconner/fix/refresh-token-optional
fix: don't refresh access token if autoRefreshToken is disabled
2 parents f131300 + 804fcba commit d8a35f0

File tree

3 files changed

+77
-15
lines changed

3 files changed

+77
-15
lines changed

src/GoTrueClient.ts

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,7 +1111,16 @@ export default class GoTrueClient {
11111111
return { data: { session: currentSession }, error: null }
11121112
}
11131113

1114+
if (!currentSession.refresh_token) {
1115+
this._debug(
1116+
'#__loadSession()',
1117+
'session has no refresh token to refresh session'
1118+
)
1119+
return { data: { session: null }, error: null };
1120+
}
1121+
11141122
const { session, error } = await this._callRefreshToken(currentSession.refresh_token)
1123+
11151124
if (error) {
11161125
return { data: { session: null }, error }
11171126
}
@@ -1258,13 +1267,14 @@ export default class GoTrueClient {
12581267
}
12591268

12601269
/**
1261-
* Sets the session data from the current session. If the current session is expired, setSession will take care of refreshing it to obtain a new session.
1270+
* Sets the session data from the current session. If the current session is expired,
1271+
* setSession will take care of refreshing it to obtain a new session when a refresh token is provided and autoRefreshToken is not disabled.
12621272
* If the refresh token or access token in the current session is invalid, an error will be thrown.
1263-
* @param currentSession The current session that minimally contains an access token and refresh token.
1273+
* @param currentSession The current session that minimally contains an access token.
12641274
*/
12651275
async setSession(currentSession: {
12661276
access_token: string
1267-
refresh_token: string
1277+
refresh_token?: string
12681278
}): Promise<AuthResponse> {
12691279
await this.initializePromise
12701280

@@ -1275,10 +1285,10 @@ export default class GoTrueClient {
12751285

12761286
protected async _setSession(currentSession: {
12771287
access_token: string
1278-
refresh_token: string
1288+
refresh_token?: string
12791289
}): Promise<AuthResponse> {
12801290
try {
1281-
if (!currentSession.access_token || !currentSession.refresh_token) {
1291+
if (!currentSession.access_token) {
12821292
throw new AuthSessionMissingError()
12831293
}
12841294

@@ -1293,6 +1303,10 @@ export default class GoTrueClient {
12931303
}
12941304

12951305
if (hasExpired) {
1306+
if (!this.autoRefreshToken || !currentSession.refresh_token) {
1307+
return { data: { user: null, session: null }, error: null }
1308+
}
1309+
12961310
const { session: refreshedSession, error } = await this._callRefreshToken(
12971311
currentSession.refresh_token
12981312
)
@@ -1303,12 +1317,15 @@ export default class GoTrueClient {
13031317
if (!refreshedSession) {
13041318
return { data: { user: null, session: null }, error: null }
13051319
}
1320+
13061321
session = refreshedSession
13071322
} else {
13081323
const { data, error } = await this._getUser(currentSession.access_token)
1324+
13091325
if (error) {
13101326
throw error
13111327
}
1328+
13121329
session = {
13131330
access_token: currentSession.access_token,
13141331
refresh_token: currentSession.refresh_token,
@@ -1337,11 +1354,11 @@ export default class GoTrueClient {
13371354
* If the current session's refresh token is invalid, an error will be thrown.
13381355
* @param currentSession The current session. If passed in, it must contain a refresh token.
13391356
*/
1340-
async refreshSession(currentSession?: { refresh_token: string }): Promise<AuthResponse> {
1357+
async refreshSession(session?: { refresh_token: string }): Promise<AuthResponse> {
13411358
await this.initializePromise
13421359

13431360
return await this._acquireLock(-1, async () => {
1344-
return await this._refreshSession(currentSession)
1361+
return await this._refreshSession(session)
13451362
})
13461363
}
13471364

@@ -1350,20 +1367,22 @@ export default class GoTrueClient {
13501367
}): Promise<AuthResponse> {
13511368
try {
13521369
return await this._useSession(async (result) => {
1353-
if (!currentSession) {
1370+
let oldSession: Pick<Session, 'refresh_token'> | null = currentSession ? { ...currentSession } : null;
1371+
1372+
if (!oldSession) {
13541373
const { data, error } = result
13551374
if (error) {
13561375
throw error
13571376
}
13581377

1359-
currentSession = data.session ?? undefined
1378+
oldSession = data.session;
13601379
}
13611380

1362-
if (!currentSession?.refresh_token) {
1381+
if (!oldSession?.refresh_token) {
13631382
throw new AuthSessionMissingError()
13641383
}
13651384

1366-
const { session, error } = await this._callRefreshToken(currentSession.refresh_token)
1385+
const { session, error } = await this._callRefreshToken(oldSession.refresh_token)
13671386
if (error) {
13681387
return { data: { user: null, session: null }, error: error }
13691388
}
@@ -1822,7 +1841,6 @@ export default class GoTrueClient {
18221841
typeof maybeSession === 'object' &&
18231842
maybeSession !== null &&
18241843
'access_token' in maybeSession &&
1825-
'refresh_token' in maybeSession &&
18261844
'expires_at' in maybeSession
18271845

18281846
return isValidSession

src/lib/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ export interface Session {
241241
/**
242242
* A one-time used refresh token that never expires.
243243
*/
244-
refresh_token: string
244+
refresh_token?: string
245245
/**
246246
* The number of seconds until the token expires (since it was issued). Returned when a login is confirmed.
247247
*/

test/GoTrueClient.test.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,50 @@ describe('GoTrueClient', () => {
139139
expect(user?.user_metadata).toMatchObject({ hello: 'world' })
140140
})
141141

142+
test('setSession should return no error without a passed-in refresh token', async () => {
143+
const { email, password } = mockUserCredentials()
144+
145+
const { error, data } = await authWithSession.signUp({
146+
email,
147+
password,
148+
})
149+
expect(error).toBeNull()
150+
expect(data.session).not.toBeNull()
151+
152+
const {
153+
data: { session },
154+
error: setSessionError,
155+
} = await authWithSession.setSession({
156+
// @ts-expect-error 'data.session should not be null because of the assertion above'
157+
access_token: data.session.access_token
158+
})
159+
expect(setSessionError).toBeNull()
160+
expect(session).not.toBeNull()
161+
expect(session!.user).not.toBeNull()
162+
expect(session!.expires_in).not.toBeNull()
163+
expect(session!.expires_at).not.toBeNull()
164+
expect(session!.access_token).not.toBeNull()
165+
expect(session!.refresh_token).not.toBeNull()
166+
expect(session!.token_type).toStrictEqual('bearer')
167+
168+
/**
169+
* getSession has been added to verify setSession is also saving
170+
* the session, not just returning it.
171+
*/
172+
const { data: getSessionData, error: getSessionError } = await authWithSession.getSession()
173+
expect(getSessionError).toBeNull()
174+
expect(getSessionData).not.toBeNull()
175+
176+
const {
177+
data: { user },
178+
error: updateError,
179+
} = await authWithSession.updateUser({ data: { hello: 'world' } })
180+
181+
expect(updateError).toBeNull()
182+
expect(user).not.toBeNull()
183+
expect(user?.user_metadata).toMatchObject({ hello: 'world' })
184+
})
185+
142186
test('getSession() should return the currentUser session', async () => {
143187
const { email, password } = mockUserCredentials()
144188

@@ -265,7 +309,7 @@ describe('GoTrueClient', () => {
265309
// verify the deferred has been reset and successive calls can be made
266310
// @ts-expect-error 'Allow access to private _callRefreshToken()'
267311
const { session: session3, error: error3 } = await authWithSession._callRefreshToken(
268-
data.session!.refresh_token
312+
data.session!.refresh_token!
269313
)
270314

271315
expect(error3).toBeNull()
@@ -307,7 +351,7 @@ describe('GoTrueClient', () => {
307351
// vreify the deferred has been reset and successive calls can be made
308352
// @ts-expect-error 'Allow access to private _callRefreshToken()'
309353
const { session: session3, error: error3 } = await authWithSession._callRefreshToken(
310-
data.session!.refresh_token
354+
data.session!.refresh_token!
311355
)
312356

313357
expect(error3).toBeNull()

0 commit comments

Comments
 (0)