Skip to content

Commit 70fe14f

Browse files
authored
feat: add refresh token to auth refresh calls without an access token present (#203)
* feat: add refresh token to auth refresh calls without an access token present * test: add test for attemptRefreshingSession w/ cleared st-access-token
1 parent c3991fd commit 70fe14f

File tree

5 files changed

+68
-7
lines changed

5 files changed

+68
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [unreleased]
99

10+
### Changes
11+
12+
- Adding refresh tokens to refresh calls even if access token isn't present to make manual testing easier.
13+
1014
## [16.0.2] - 2023-03-07
1115
- Exposed getGlobalClaimValidators function via utils.
1216

bundle/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/build/fetch.js

Lines changed: 5 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/ts/fetch.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ export async function onUnauthorisedResponse(
520520
// in the first place.
521521
return { result: "SESSION_EXPIRED", error };
522522
}
523+
523524
logDebugMessage("onUnauthorisedResponse: sending API_ERROR");
524525
return { result: "API_ERROR", error };
525526
} finally {
@@ -722,9 +723,11 @@ async function setAuthorizationHeaderIfRequired(clonedHeaders: Headers, addRefre
722723
const refreshToken = await getTokenForHeaderAuth("refresh");
723724

724725
// We don't always need the refresh token because that's only required by the refresh call
725-
// Still, we only add the Authorization header if both are present, because we are planning to add an option to expose the
726-
// access token to the frontend while using cookie based auth - so that users can get the access token to use
727-
if (accessToken !== undefined && refreshToken !== undefined) {
726+
// Still, we only add the access token to Authorization header if both are present, because we are planning to add an option to expose the
727+
// access token to the frontend while using cookie based auth - so that users can get the access token without using header based auth
728+
// We can add the refresh token even if only that one is present, to make manual testing easier - you can then
729+
// force a refresh by just deleting the access token.
730+
if ((addRefreshToken || accessToken !== undefined) && refreshToken !== undefined) {
728731
// the Headers class normalizes header names so we don't have to worry about casing
729732
if (clonedHeaders.has("Authorization")) {
730733
logDebugMessage("setAuthorizationHeaderIfRequired: Authorization header defined by the user, not adding");

test/fetch.headers.test.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,58 @@ describe("Fetch AuthHttpRequest class tests with headers", function () {
805805
}
806806
});
807807

808+
it("test with fetch that attemptRefreshingSession is working correctly after removing st-access-token", async function () {
809+
await startST(5);
810+
const browser = await puppeteer.launch({
811+
args: ["--no-sandbox", "--disable-setuid-sandbox"]
812+
});
813+
try {
814+
const page = await browser.newPage();
815+
await page.goto(BASE_URL + "/index.html", { waitUntil: "load" });
816+
await page.addScriptTag({ path: `./bundle/bundle.js`, type: "text/javascript" });
817+
818+
await page.evaluate(async () => {
819+
let BASE_URL = "http://localhost.org:8080";
820+
supertokens.init({
821+
apiDomain: BASE_URL,
822+
tokenTransferMethod: "header"
823+
});
824+
let userId = "testing-supertokens-website";
825+
console.log("0");
826+
827+
// send api request to login
828+
let loginResponse = await fetch(`${BASE_URL}/login`, {
829+
method: "post",
830+
headers: {
831+
Accept: "application/json",
832+
"Content-Type": "application/json"
833+
},
834+
body: JSON.stringify({ userId })
835+
});
836+
assertEqual(await loginResponse.text(), userId);
837+
838+
document.cookie = "st-access-token=;expires=Thu, 01 Jan 1970 00:00:01 GMT";
839+
840+
let attemptRefresh = await supertokens.attemptRefreshingSession();
841+
assertEqual(attemptRefresh, true);
842+
843+
//check that the number of times the refresh API was called is 1
844+
assertEqual(await getNumberOfTimesRefreshCalled(), 1);
845+
846+
let getSessionResponse = await fetch(`${BASE_URL}/`);
847+
assertEqual(await getSessionResponse.text(), userId);
848+
849+
//check that the number of times the refresh API was called is still 1
850+
assertEqual(await getNumberOfTimesRefreshCalled(), 1);
851+
});
852+
853+
const originalCookies = (await page._client.send("Network.getAllCookies")).cookies;
854+
assert(originalCookies.find(c => c.name === "st-access-token"));
855+
} finally {
856+
await browser.close();
857+
}
858+
});
859+
808860
// multiple API calls in parallel when access token is expired (100 of them) and only 1 refresh should be called*****
809861
it("test with fetch that multiple API calls in parallel when access token is expired, only 1 refresh should be called", async function () {
810862
await startST(15);

0 commit comments

Comments
 (0)