Skip to content
This repository was archived by the owner on Mar 4, 2026. It is now read-only.

Commit e90b135

Browse files
committed
Invalidate access tokens when session id changes (#1142)
* invalidate access token when session id changes * also update cache logic to decode new jwt format of reddit_session
1 parent 65f7f23 commit e90b135

2 files changed

Lines changed: 34 additions & 6 deletions

File tree

extension/data/background/handlers/cache.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,9 @@ async function getSessionUserID (sender) {
9595
}
9696

9797
if (redditSessionCookie) {
98-
// The session value contains comma seperated values. The first one is the the userid in base10.
99-
// As reddit uses base36 everywhere else we convert the ID to that so things are easier to debug.
100-
const redditUserIdBase10 = decodeURIComponent(redditSessionCookie.value).split(',')[0];
101-
redditUserIdBase36 = parseInt(redditUserIdBase10).toString(36);
98+
// this cookie is a JWT now, fun. decode its payload and get the
99+
// `sub`ject, removing `t3_`
100+
redditUserIdBase36 = JSON.parse(atob(redditSessionCookie.value.split('.')[1])).sub.slice(3);
102101
} else {
103102
redditUserIdBase36 = 'noSessionFallback';
104103
}

extension/data/background/handlers/webrequest.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,47 @@
11
import browser from 'webextension-polyfill';
22
import {messageHandlers} from '../messageHandling';
33

4+
async function getSessionPrefix () {
5+
const cookieInfo = {url: 'https://reddit.com', name: 'reddit_session'};
6+
let redditSessionCookie;
7+
try {
8+
redditSessionCookie = await browser.cookies.get(cookieInfo);
9+
} catch (error) {
10+
// retry with first-party domain
11+
cookieInfo.firstPartyDomain = 'reddit.com';
12+
redditSessionCookie = await browser.cookies.get(cookieInfo);
13+
}
14+
15+
if (redditSessionCookie) {
16+
// use the decoded JWT ID changing as a sign that we need to get a new
17+
// access token, because changing users invalidates the old token
18+
const decodedJWTPayload = JSON.parse(atob(redditSessionCookie.value.split('.')[1]));
19+
return decodedJWTPayload.jti;
20+
} else {
21+
return 'noSessionFallback';
22+
}
23+
}
24+
425
/**
526
* Retrieves an OAuth token from /svc/shreddit/token
627
* @param {number} [tries=1] Number of tries to get the token (recursive)
728
* @returns {Promise<Object>} An object with properties `accessToken` and `expires`.
829
*/
930
async function getOAuthTokens (tries = 1) {
31+
// Attempt to use cached token if it hasn't expired
32+
33+
// make currently-logged-in user part of the storage key so we don't
34+
// accidentally use the wrong access token after switching accounts
35+
const currentUserID = await getSessionPrefix();
36+
const storageKey = `tb-accessToken-${currentUserID}`;
1037
// HACK: the storage API is so so dumb but I do not have the energy to do this properly rn
11-
const cachedToken = (await browser.storage.local.get('tb-accessToken'))['tb-accessToken'];
38+
const cachedToken = (await browser.storage.local.get(storageKey))[storageKey];
1239
if (cachedToken && cachedToken.expires > Date.now()) {
1340
return cachedToken;
1441
}
1542

43+
// No luck, fetch new token
44+
1645
// Grab the csrf_token cookie
1746
const cookieInfo = {url: 'https://sh.reddit.com', name: 'csrf_token'};
1847
let csrf_token;
@@ -39,7 +68,7 @@ async function getOAuthTokens (tries = 1) {
3968
accessToken: tokenData.token,
4069
expires: tokenData.expires,
4170
};
42-
await browser.storage.local.set({'tb-accessToken': result});
71+
await browser.storage.local.set({[storageKey]: result});
4372
return result;
4473
} else {
4574
throw new Error(`Error getting accessToken from /svc/shreddit/token. Response text: ${await resp.text()}`);

0 commit comments

Comments
 (0)