
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
graphql-knifey
Advanced tools
Reuse code for generic GraphQL projects with built-in session/cookie authentication support.
import diContainer, { apolloContextLDEGen, apolloServerLDEGen, appConfigLDEGen } from 'graphql-knifey';
// create your injection dict
const myInjectionDict = {
// map config from env
apolloContext: apolloContextLDEGen({
userService: 'userService',
tokenAuthService: 'tokenAuthService',
}),
apolloServer: apolloServerLDEGen(resolvers, graphqlSchema),
aService: aServiceLoadDictElement,
// ... can override graphql-knifey entries
};
// pass it to graphql-knifey's default one
diContainer.addToLoadDict(myInjectionDict);
graphql-knifey now includes comprehensive session management and cookie-based authentication support, making it easy to migrate from JWT tokens to secure HTTP-only cookies.
import {
apolloContextWithAuthLDEGen,
sessionServiceLDEGen,
cookieStrategyLDEGen,
apolloStandaloneServerLDEGen
} from 'graphql-knifey';
diContainer.addToLoadDict({
// Session service with Redis storage
sessionService: sessionServiceLDEGen({
sessionTTL: 7200, // 2 hours
refreshTTL: 604800, // 7 days
}),
// Cookie-based authentication strategy
authStrategy: cookieStrategyLDEGen(),
// Configure authentication mode in appConfig
appConfig: appConfigLDEGen({
authMode: 'cookie', // 'cookie' | 'jwt' | 'hybrid'
sessionCookieName: 'sid',
refreshCookieName: 'rid',
}),
// Apollo context with auth support
apolloContext: apolloContextWithAuthLDEGen({
userService: 'userService',
authService: 'authService',
// any other services needed by resolvers
}),
// Apollo server (already configured for cookies)
apolloServer: apolloStandaloneServerLDEGen(resolvers, typeDefs),
});
The SessionService
manages server-side sessions with Redis or any compatible storage:
import { SessionService, SessionServiceInterface } from 'graphql-knifey';
interface SessionData {
userId: string;
metadata?: Record<string, any>;
}
// Methods available:
sessionService.create(userId, metadata) // Returns { sessionId, refreshId }
sessionService.validate(sessionId) // Returns SessionData or null
sessionService.refresh(refreshId) // Returns new { sessionId, refreshId }
sessionService.revoke(sessionId) // Revokes a session
sessionService.revokeAllUserSessions(userId) // Revokes all user sessions
Three strategies are provided for different use cases:
import { cookieStrategyLDEGen } from 'graphql-knifey';
authStrategy: cookieStrategyLDEGen()
import { jwtStrategyLDEGen } from 'graphql-knifey';
authStrategy: jwtStrategyLDEGen()
import { hybridStrategyLDEGen } from 'graphql-knifey';
authStrategy: hybridStrategyLDEGen(true) // true = prefer cookies
The enhanced Apollo context provides auth helpers in your resolvers:
// Your resolver context will include:
interface AuthContextResult {
// Request/Response
req: Request;
res: Response;
IP: string;
// Auth state
authenticated: boolean;
userId?: string;
user?: any;
// Cookie helpers
sessionId?: string;
refreshId?: string;
setAuthCookies: (args: {
sessionId?: string;
refreshId?: string;
sessionMaxAgeSec?: number;
refreshMaxAgeSec?: number;
}) => void;
clearAuthCookies: () => void;
// Authentication configuration used
config: {
authStrategy?: AuthStrategy;
sessionService?: SessionServiceInterface;
sessionAdapter?: any;
}
// Backward compatibility
token?: string;
// Your injected services
[key: string]: any;
}
const resolvers = {
Mutation: {
login: async (_, { email, password }, context) => {
const user = await context.authService.verify(email, password);
if (!user) return { success: false };
// Create session using the configured session service
const { sessionId, refreshId } = await context.config.sessionService.create(user.id);
// Set HTTP-only cookies
context.setAuthCookies({
sessionId,
refreshId,
sessionMaxAgeSec: 7200, // 2 hours
refreshMaxAgeSec: 604800, // 7 days
});
return { success: true, user };
},
logout: async (_, __, context) => {
if (context.sessionId && context.config.sessionService) {
await context.config.sessionService.revoke(context.sessionId);
}
context.clearAuthCookies();
return { success: true };
},
refreshSession: async (_, __, context) => {
if (!context.refreshId || !context.config.sessionService) {
return { success: false };
}
const result = await context.config.sessionService.refresh(context.refreshId);
if (!result) return { success: false };
context.setAuthCookies({
sessionId: result.sessionId,
refreshId: result.refreshId,
});
return { success: true };
}
},
Query: {
me: async (_, __, context) => {
if (!context.authenticated) {
throw new Error('Not authenticated');
}
return context.user;
}
}
};
The authentication context is created through a clean separation of concerns:
appConfig
apolloContextWithAuthLDEGen
creates the context factory functioncreateAuthContext
handles the actual authentication logic per requestimport { createAuthContext, apolloContextWithAuthLDEGen } from 'graphql-knifey';
// The loader generator fetches configuration and services
apolloContext: apolloContextWithAuthLDEGen({
// Services to inject into resolver context
userService: 'userService',
postService: 'postService',
})
// Behind the scenes, createAuthContext is called for each request:
// createAuthContext(params, { config, sharedContext })
The createAuthContext
function:
The SessionToJWTAdapter
helps existing JWT-based code work with sessions:
import { sessionToJWTAdapterLDEGen, authServiceAdapterLDEGen } from 'graphql-knifey';
diContainer.addToLoadDict({
// Makes sessions work like JWTs for existing code
sessionAdapter: sessionToJWTAdapterLDEGen(),
// Wraps existing auth service to support sessions
authServiceAdapter: authServiceAdapterLDEGen(),
// Use hybrid mode during migration
authStrategy: hybridStrategyLDEGen(true),
});
Phase 1: Add Session Support (Hybrid Mode)
authMode: 'hybrid' // Supports both JWT and cookies
Phase 2: Migrate Clients
credentials: 'include'
Authorization
header logicPhase 3: Cookie-Only Mode
authMode: 'cookie' // Only cookies accepted
Add these to your .env
:
# Cookie Configuration
COOKIE_SECRET=your-secret-key-here
COOKIE_DOMAIN=.example.com
SESSION_COOKIE_NAME=sid
REFRESH_COOKIE_NAME=rid
SESSION_TTL=7200
REFRESH_TTL=604800
AUTH_MODE=hybrid # cookie | jwt | hybrid
const appConfigGen = (env) => ({
// ... existing config
// Cookie/session configuration
cookieSecret: env.COOKIE_SECRET,
cookieDomain: env.COOKIE_DOMAIN,
accessCookieName: env.SESSION_COOKIE_NAME || 'sid',
refreshCookieName: env.REFRESH_COOKIE_NAME || 'rid',
sessionTTL: parseInt(env.SESSION_TTL) || 7200,
refreshTTL: parseInt(env.REFRESH_TTL) || 604800,
authMode: env.AUTH_MODE || 'hybrid',
});
import diContainer, { appConfigLDEGen, mergeToDefaultAppConfigMap } from 'graphql-knifey';
import localAppConfigMap from '../config/appConfig';
// create your injection dict
const myInjectionDict = {
// override defaultAppConfig with a merge between defaultAppConfigMap and your localAppConfigMap
appConfig: appConfigLDEGen(mergeToDefaultAppConfigMap(localAppConfigMap)),
// ... rest of entries as in previous example
};
// pass it to graphql-knifey's default one
diContainer.addToLoadDict(myInjectionDict);
Cookies in a GraphQL API can get tricky because they involve both server CORS setup and browser behavior. Let's break it down in context of two setups (public vs. subgraph).
Unlike headers (Authorization: Bearer ...
), cookies are automatically attached by browsers only if three conditions are satisfied:
CORS allows credentials On the server:
cors({ origin: "https://app.example.com", credentials: true })
On the client (fetch/Apollo Client):
fetch("/graphql", {
method: "POST",
credentials: "include", // <— critical
});
Cookie attributes must be set properly:
Secure
: required if served over HTTPS (mandatory in Chrome if SameSite=None
).HttpOnly
: prevents JS from reading the cookie — highly recommended for session tokens.SameSite
:
Lax
(default): cookie sent for top-level navigation (GET), but not for subrequests (like GraphQL fetch from a SPA).Strict
: cookie only sent if the site is the same origin — breaks cross-origin APIs.None
: cookie always sent, but must also have Secure
.Domain and path must cover your frontend.
Example: if API is on api.example.com
and frontend on app.example.com
, you'd typically set:
Set-Cookie: session=abc123; Domain=.example.com; Path=/; SameSite=None; Secure; HttpOnly
Here you must configure cookies + CORS correctly if you use them for auth:
Server CORS config:
app.use(
"/graphql",
cors({
origin: "https://app.example.com",
credentials: true, // must be true for cookies
}),
express.json(),
expressMiddleware(server, { context })
);
Client fetch/Apollo Client config:
const client = new ApolloClient({
uri: "https://api.example.com/graphql",
cache: new InMemoryCache(),
credentials: "include", // tells browser to send cookies
});
Cookie issue example:
If you forget SameSite=None; Secure
, the cookie won't be sent in cross-origin requests (browser silently drops it). This is the #1 cause of "why isn't my cookie auth working?"
Cookies almost never matter here:
Authorization
) to the subgraphs.👉 So: you don't need cookie setup on the subgraph at all.
For public graph:
SameSite=None; Secure; HttpOnly
for cross-origin.credentials: true
on both sides.For subgraph: ignore cookies; forward an Authorization
header from the gateway.
Session Security:
All exports are fully typed. Key types include:
import type {
SessionServiceInterface,
SessionData,
AuthStrategy,
AuthResult,
ValidationResult,
PublicGraphContextWithAuth,
} from 'graphql-knifey';
ISC
FAQs
Tools for dealing with graphql server side
The npm package graphql-knifey receives a total of 1,428 weekly downloads. As such, graphql-knifey popularity was classified as popular.
We found that graphql-knifey demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.