Skip to content

Commit

Permalink
feat: add refresh token to auth refresh calls without an access token…
Browse files Browse the repository at this point in the history
… 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
  • Loading branch information
porcellus authored Mar 13, 2023
1 parent c3991fd commit 70fe14f
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 7 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

### Changes

- Adding refresh tokens to refresh calls even if access token isn't present to make manual testing easier.

## [16.0.2] - 2023-03-07
- Exposed getGlobalClaimValidators function via utils.

Expand Down
2 changes: 1 addition & 1 deletion bundle/bundle.js

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions lib/build/fetch.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions lib/ts/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ export async function onUnauthorisedResponse(
// in the first place.
return { result: "SESSION_EXPIRED", error };
}

logDebugMessage("onUnauthorisedResponse: sending API_ERROR");
return { result: "API_ERROR", error };
} finally {
Expand Down Expand Up @@ -722,9 +723,11 @@ async function setAuthorizationHeaderIfRequired(clonedHeaders: Headers, addRefre
const refreshToken = await getTokenForHeaderAuth("refresh");

// We don't always need the refresh token because that's only required by the refresh call
// Still, we only add the Authorization header if both are present, because we are planning to add an option to expose the
// access token to the frontend while using cookie based auth - so that users can get the access token to use
if (accessToken !== undefined && refreshToken !== undefined) {
// 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
// access token to the frontend while using cookie based auth - so that users can get the access token without using header based auth
// We can add the refresh token even if only that one is present, to make manual testing easier - you can then
// force a refresh by just deleting the access token.
if ((addRefreshToken || accessToken !== undefined) && refreshToken !== undefined) {
// the Headers class normalizes header names so we don't have to worry about casing
if (clonedHeaders.has("Authorization")) {
logDebugMessage("setAuthorizationHeaderIfRequired: Authorization header defined by the user, not adding");
Expand Down
52 changes: 52 additions & 0 deletions test/fetch.headers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,58 @@ describe("Fetch AuthHttpRequest class tests with headers", function () {
}
});

it("test with fetch that attemptRefreshingSession is working correctly after removing st-access-token", async function () {
await startST(5);
const browser = await puppeteer.launch({
args: ["--no-sandbox", "--disable-setuid-sandbox"]
});
try {
const page = await browser.newPage();
await page.goto(BASE_URL + "/index.html", { waitUntil: "load" });
await page.addScriptTag({ path: `./bundle/bundle.js`, type: "text/javascript" });

await page.evaluate(async () => {
let BASE_URL = "http://localhost.org:8080";
supertokens.init({
apiDomain: BASE_URL,
tokenTransferMethod: "header"
});
let userId = "testing-supertokens-website";
console.log("0");

// send api request to login
let loginResponse = await fetch(`${BASE_URL}/login`, {
method: "post",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({ userId })
});
assertEqual(await loginResponse.text(), userId);

document.cookie = "st-access-token=;expires=Thu, 01 Jan 1970 00:00:01 GMT";

let attemptRefresh = await supertokens.attemptRefreshingSession();
assertEqual(attemptRefresh, true);

//check that the number of times the refresh API was called is 1
assertEqual(await getNumberOfTimesRefreshCalled(), 1);

let getSessionResponse = await fetch(`${BASE_URL}/`);
assertEqual(await getSessionResponse.text(), userId);

//check that the number of times the refresh API was called is still 1
assertEqual(await getNumberOfTimesRefreshCalled(), 1);
});

const originalCookies = (await page._client.send("Network.getAllCookies")).cookies;
assert(originalCookies.find(c => c.name === "st-access-token"));
} finally {
await browser.close();
}
});

// multiple API calls in parallel when access token is expired (100 of them) and only 1 refresh should be called*****
it("test with fetch that multiple API calls in parallel when access token is expired, only 1 refresh should be called", async function () {
await startST(15);
Expand Down

0 comments on commit 70fe14f

Please sign in to comment.