Skip to content

Commit ed25362

Browse files
committed
Refactor the logic around handling public tokens
This introduces TokenSource interface which allows us to retrieve the tokens either from cookies or from headers (or both). When cookies are used it also adds additional security items like fingerprints and setting some cookies as http-only and some not
1 parent 9f6fbde commit ed25362

14 files changed

+782
-287
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,17 @@ When a federated services creates a new token (when non exist) it can also
2020
return a refresh token in the `x-refresh-token` header. The gateway will then
2121
encrypt all refresh tokens and encrypt them before passing them to the client
2222
as `x-refresh-token` header.
23+
24+
25+
# Token sources
26+
27+
28+
## Cookie Token Source
29+
This token source is used for browser clients to safely store the token. It is
30+
implemented via 4 cookies:
31+
- accessToken - The JWT token
32+
- tokenFingerprint - A random string that is used to protect the AccessToken
33+
cookie from CSRF attacks. It is stored as HTTP_ONLY cookie.
34+
- refreshToken - The refresh token, if any. It is stored as HTTP_ONLY cookie.
35+
- refreshTokenExists - A boolean value that indicates if a refresh token exists
36+
for the user. It is used to determine if the user is new or not.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,15 @@
4343
"devDependencies": {
4444
"@changesets/cli": "^2.26.2",
4545
"@sentry/types": "7.55.0",
46+
"@types/cookie-parser": "^1.4.3",
4647
"@types/crypto-js": "4.1.1",
48+
"@types/express": "^4.17.17",
4749
"@types/lodash-es": "4.17.7",
4850
"@typescript-eslint/eslint-plugin": "^5.60.1",
4951
"@vitest/coverage-v8": "0.32.2",
5052
"eslint": "^8.40.0",
5153
"eslint-plugin-unused-imports": "^2.0.0",
54+
"node-mocks-http": "^1.12.2",
5255
"tsup": "^7.1.0",
5356
"typescript": "^5.1.5",
5457
"vitest": "0.32.2"

pnpm-lock.yaml

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

src/datasource.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class FederatedGraphQLDataSource extends RemoteGraphQLDataSource<PublicFe
6262
if (!context.federatedToken) {
6363
context.federatedToken = new PublicFederatedToken();
6464
}
65-
context.federatedToken.loadRefreshToken(refreshToken);
65+
context.federatedToken.loadRefreshToken(refreshToken, true);
6666
}
6767
return response;
6868
}

src/fingerprint.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { randomBytes } from "crypto";
2+
import { createHash } from "node:crypto";
3+
4+
export const generateFingerprint = (): string => {
5+
const length = 32;
6+
const buffer = randomBytes(Math.ceil(length / 2));
7+
return buffer.toString("hex").slice(0, length);
8+
};
9+
10+
export const hashFingerprint = (fingerprint: string): string => {
11+
const hash = createHash("sha256");
12+
hash.update(fingerprint);
13+
return hash.digest("hex");
14+
};
15+
16+
export const validateFingerprint = (
17+
fingerprint: string,
18+
hashedFingerprint: string
19+
) => hashFingerprint(fingerprint) === hashedFingerprint;

0 commit comments

Comments
 (0)