Skip to content

Commit fb1255d

Browse files
committed
Improved access token cookie handling
1 parent 3adf198 commit fb1255d

File tree

1 file changed

+22
-14
lines changed

1 file changed

+22
-14
lines changed

packages/stack/src/lib/stack-app.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,15 @@ class _StackClientAppImpl<HasTokenStore extends boolean, ProjectId extends strin
412412
protected get _refreshTokenCookieName() {
413413
return `stack-refresh-${this.projectId}`;
414414
}
415+
protected _getTokensFromCookies(cookies: { refreshTokenCookie: string | null, accessTokenCookie: string | null }): TokenObject {
416+
const refreshToken = cookies.refreshTokenCookie;
417+
const accessTokenObject = cookies.accessTokenCookie?.startsWith('[\"') ? JSON.parse(cookies.accessTokenCookie) : null; // gotta check for validity first for backwards-compat, and also in case someone messes with the cookie value
418+
const accessToken = accessTokenObject && refreshToken === accessTokenObject[0] ? accessTokenObject[1] : null; // if the refresh token has changed, the access token is invalid
419+
return {
420+
refreshToken,
421+
accessToken,
422+
};
423+
}
415424
protected get _accessTokenCookieName() {
416425
// The access token, unlike the refresh token, should not depend on the project ID. We never want to store the
417426
// access token in cookies more than once because of how big it is (there's a limit of 4096 bytes for all cookies
@@ -425,15 +434,14 @@ class _StackClientAppImpl<HasTokenStore extends boolean, ProjectId extends strin
425434
}
426435

427436
if (this._storedCookieTokenStore === null) {
428-
const getCurrentValue = (old: TokenObject | null) => {
429-
const refreshToken = getCookie(this._refreshTokenCookieName) ?? getCookie('stack-refresh'); // keep old cookie name for backwards-compatibility
437+
const getCurrentValue = (old: TokenObject | null) => {
438+
const tokens = this._getTokensFromCookies({
439+
refreshTokenCookie: getCookie(this._refreshTokenCookieName) ?? getCookie('stack-refresh'), // keep old cookie name for backwards-compatibility
440+
accessTokenCookie: getCookie(this._accessTokenCookieName),
441+
});
430442
return {
431-
refreshToken,
432-
433-
// if there is an access token in memory already, and the refresh token hasn't changed, don't update the
434-
// access token based on cookies (access token cookies may be set by another project on the same domain)
435-
// see the comment in _accessTokenCookieName for more information
436-
accessToken: old !== null && refreshToken === old.refreshToken ? old.accessToken : getCookie(this._accessTokenCookieName),
443+
refreshToken: tokens.refreshToken,
444+
accessToken: tokens.accessToken ?? (old?.refreshToken === tokens.refreshToken ? old.accessToken : null),
437445
};
438446
};
439447
this._storedCookieTokenStore = new Store<TokenObject>(getCurrentValue(null));
@@ -451,7 +459,7 @@ class _StackClientAppImpl<HasTokenStore extends boolean, ProjectId extends strin
451459
this._storedCookieTokenStore.onChange((value) => {
452460
try {
453461
setOrDeleteCookie(this._refreshTokenCookieName, value.refreshToken, { maxAge: 60 * 60 * 24 * 365 });
454-
setOrDeleteCookie(this._accessTokenCookieName, value.accessToken, { maxAge: 60 * 60 * 24 });
462+
setOrDeleteCookie(this._accessTokenCookieName, value.accessToken ? JSON.stringify([value.refreshToken, value.accessToken]) : null, { maxAge: 60 * 60 * 24 });
455463
deleteCookie('stack-refresh'); // delete cookie name from previous versions (for backwards-compatibility)
456464
hasSucceededInWriting = true;
457465
} catch (e) {
@@ -478,15 +486,15 @@ class _StackClientAppImpl<HasTokenStore extends boolean, ProjectId extends strin
478486
if (isBrowserLike()) {
479487
return this._getCookieTokenStore();
480488
} else {
481-
const refreshToken = getCookie(this._refreshTokenCookieName) ?? getCookie('stack-refresh'); // keep old cookie name for backwards-compatibility
482-
const store = new Store<TokenObject>({
483-
refreshToken,
484-
accessToken: getCookie(this._accessTokenCookieName),
489+
const tokens = this._getTokensFromCookies({
490+
refreshTokenCookie: getCookie(this._refreshTokenCookieName) ?? getCookie('stack-refresh'), // keep old cookie name for backwards-compatibility
491+
accessTokenCookie: getCookie(this._accessTokenCookieName),
485492
});
493+
const store = new Store<TokenObject>(tokens);
486494
store.onChange((value) => {
487495
try {
488496
setOrDeleteCookie(this._refreshTokenCookieName, value.refreshToken, { maxAge: 60 * 60 * 24 * 365 });
489-
setOrDeleteCookie(this._accessTokenCookieName, value.accessToken, { maxAge: 60 * 60 * 24 });
497+
setOrDeleteCookie(this._accessTokenCookieName, value.accessToken ? JSON.stringify([value.refreshToken, value.accessToken]) : null, { maxAge: 60 * 60 * 24 });
490498
} catch (e) {
491499
// ignore
492500
}

0 commit comments

Comments
 (0)