
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
graphql-knifey
Advanced tools
A modular, dependency-injection based toolkit for building GraphQL servers with Apollo Server. Supports both standalone and federated subgraph configurations.
npm install graphql-knifey@5.0.0
# For standalone servers (most common) - no additional dependencies needed!
# For federated subgraph servers only:
npm install @apollo/subgraph
import {
diContainer,
apolloStandaloneServerModularLDGen,
loadSchema,
GQLResolverDict
} from 'graphql-knifey';
// Define your GraphQL schema
const graphqlSchema = loadSchema('./src/graphql/schema/schema.graphql');
// Type-safe resolvers
const resolvers: GQLResolverDict<MyContext> = {
Query: {
hello: () => 'Hello World!'
}
};
// Add Apollo server to the DI container
diContainer.addToLoadDict({
...apolloStandaloneServerModularLDGen(resolvers, graphqlSchema)
});
// Start the server
await diContainer.get('apolloServer');
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 new modular architecture provides flexible middleware configuration:
import { MiddlewarePathConfig } from 'graphql-knifey';
const middlewareConfig: MiddlewarePathConfig = {
'/graphql': [
{ name: 'expressTrustProxyMiddleware', priority: 100 },
{ name: 'expressCorsMiddleware', priority: 90 },
{ name: 'expressCookieParserMiddleware', priority: 80 },
{ name: 'expressBodyParserMiddleware', priority: 70 },
{ name: 'expressGraphqlMiddleware', required: true, priority: -100 },
],
'/healthz': [
{ name: 'expressHealthCheckMiddleware' }
]
};
// Pass custom configuration
const loaders = apolloStandaloneServerModularLDGen(
resolvers,
typeDefs,
undefined, // use default loader handles
middlewareConfig
);
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 {
// Authentication types
SessionServiceInterface,
SessionData,
AuthStrategy,
AuthResult,
ValidationResult,
PublicGraphContextWithAuth,
// Middleware configuration types
MiddlewareAttacher,
MiddlewareConfig,
MiddlewarePathConfig,
// Apollo/GraphQL types
GQLResolverDict,
Resolvers,
ApolloServerConfigParams,
} from 'graphql-knifey';
ISC
FAQs
Tools for dealing with graphql server side
The npm package graphql-knifey receives a total of 1,778 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
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.