Skip to content

Commit

Permalink
feat: implement envelop plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
mvantellingen committed Oct 18, 2024
1 parent 12acda7 commit 1f72aa6
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/quick-carrots-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@labdigital/federated-token-envelop": patch
---

Initial release of an Envelop plugin
1 change: 1 addition & 0 deletions packages/envelop/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/**
3 changes: 3 additions & 0 deletions packages/envelop/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: ["../../.eslintrc.cjs"],
};
19 changes: 19 additions & 0 deletions packages/envelop/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# @labdigital/federated-token-apollo

## 0.13.1

### Patch Changes

- 8cb1d63: Export `PublicFederatedTokenContext`

## 0.13.0

### Minor Changes

- 5d091fd: Split the package in a `core` and a `apollo` specific package. This makes it
possible to support other gateways/servers in the future

### Patch Changes

- Updated dependencies [5d091fd]
- @labdigital/federated-token@0.13.0
61 changes: 61 additions & 0 deletions packages/envelop/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "@labdigital/federated-token-envelop",
"version": "0.13.1",
"description": "Federate JWT tokens between GraphQL servers",
"module": "./dist/index.js",
"main": "./dist/index.cjs",
"types": "./dist/index.d.ts",
"type": "module",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"keywords": [
"graphql",
"authentication",
"yoga",
"envelope"
],
"author": "Lab Digital <opensource@labdigital.nl>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/labd/node-federated-token"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "tsup",
"test": "vitest run",
"test:ci": "vitest run --coverage",
"tsc": "tsc --noEmit",
"format": "eslint src --fix && prettier --write .",
"lint": "eslint src && prettier --check ."
},
"files": [
"dist",
"src"
],
"dependencies": {
"@envelop/core": "5.0.2",
"@labdigital/federated-token": "workspace:*"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@typescript-eslint/eslint-plugin": "^7.12.0",
"@vitest/coverage-v8": "1.6.0",
"eslint": "^8.57.0",
"eslint-plugin-unused-imports": "^4.0.0",
"node-mocks-http": "^1.14.1",
"prettier": "^3.3.1",
"tsup": "^8.1.0",
"typescript": "^5.4.5",
"vitest": "1.6.0"
},
"peerDependencies": {
"graphql": ">= 16.6.0"
}
}
1 change: 1 addition & 0 deletions packages/envelop/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { federatedAuthPlugin } from "./plugin";
59 changes: 59 additions & 0 deletions packages/envelop/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { Plugin } from "@envelop/core";
import { FederatedToken } from "@labdigital/federated-token";

type FederatedTokenContext = {
federatedToken: FederatedToken;
request: Request;
response: Response;
};

export const federatedAuthPlugin = (): Plugin<FederatedTokenContext> => ({
onContextBuilding: ({ context, extendContext }) => {
const req = context["request"] || {};

// Initialize FederatedToken and add it to the context
const federatedToken = new FederatedToken();

// Retrieve tokens from headers using the serverContext
const accessToken = req.headers.get("x-access-token") as string;
const refreshToken = req.headers.get("x-refresh-token") as string;

if (accessToken) {
federatedToken.deserializeAccessToken(accessToken);
}

if (refreshToken) {
federatedToken.loadRefreshToken(refreshToken);
}

// Extend the context with federatedToken
extendContext({ federatedToken });
},

onExecute: ({ args }) => ({
onExecuteDone: async ({ result }) => {
const { federatedToken } = args.contextValue;
const { response } = args.contextValue;

if (!federatedToken) return;

// Check if the tokens were modified and set headers accordingly
if (
federatedToken.isAccessTokenModified() ||
federatedToken.isValueModified()
) {
const serializedToken = federatedToken.serializeAccessToken();
if (serializedToken) {
response.headers.set("X-Access-Token", serializedToken);
}
}

if (federatedToken.isRefreshTokenModified()) {
const serializedRefreshToken = federatedToken.dumpRefreshToken();
if (serializedRefreshToken) {
response.headers.set("X-Refresh-Token", serializedRefreshToken);
}
}
},
}),
});
4 changes: 4 additions & 0 deletions packages/envelop/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*"]
}
13 changes: 13 additions & 0 deletions packages/envelop/tsup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineConfig } from "tsup";

export default defineConfig([
{
entry: ["src/index.ts"],
clean: true,
splitting: false,
dts: true,
sourcemap: true,
format: ["esm", "cjs"],
outDir: "dist",
},
]);
20 changes: 20 additions & 0 deletions packages/envelop/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { defineConfig } from "vitest/config";
import path from "path";

export default defineConfig({
test: {
coverage: {
provider: "v8",
all: true,
include: ["src/**/*.ts"],
reportsDirectory: "./test-reports/",
},
passWithNoTests: true,
},

resolve: {
alias: {
"~src": path.join(__dirname, "src"),
},
},
});
60 changes: 60 additions & 0 deletions pnpm-lock.yaml

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

0 comments on commit 1f72aa6

Please sign in to comment.