Context-based authentication in GraphQL - Time & Space Complexity
When using context-based authentication in GraphQL, we check user details for every request. Understanding how the time needed grows helps us keep apps fast and secure.
We want to know: how does checking user context affect the time to respond as more requests or data come in?
Analyze the time complexity of the following code snippet.
query GetUserData($userId: ID!) {
user(id: $userId) {
id
name
email
posts {
id
title
}
}
}
# Authentication context checks user token before resolving query
This query fetches user info and their posts, while the server checks the user's authentication context before answering.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Checking authentication context once per request and fetching user posts list.
- How many times: Authentication check happens once per query; fetching posts loops over each post.
Explain the growth pattern intuitively.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 posts | Authentication check + 10 post fetches |
| 100 posts | Authentication check + 100 post fetches |
| 1000 posts | Authentication check + 1000 post fetches |
Pattern observation: Authentication cost stays the same, but fetching posts grows linearly with number of posts.
Time Complexity: O(n)
This means the time to respond grows mostly with how many posts the user has, while authentication check adds a small fixed cost.
[X] Wrong: "Authentication check time grows with number of posts."
[OK] Correct: Authentication runs once per request, independent of posts count. Only fetching posts grows with post number.
Understanding how authentication and data fetching scale helps you design efficient APIs. This skill shows you can balance security and performance in real apps.
"What if the authentication context checked permissions for each post individually? How would the time complexity change?"
Practice
Solution
Step 1: Understand context-based authentication
It uses information from the request, like tokens, to verify who the user is.Step 2: Identify the main goal
The goal is to check user identity to allow or deny access to data.Final Answer:
To verify user identity using request information -> Option BQuick Check:
Context-based authentication = verify user identity [OK]
- Thinking it speeds up queries
- Confusing with data formatting
- Assuming it caches results
Solution
Step 1: Identify how context receives request info
Context function receives an object with request (req) and response (res).Step 2: Correctly extract user from request
User info is usually attached to req, so context: ({ req }) => ({ user: req.user }) is correct.Final Answer:
context: ({ req }) => ({ user: req.user }) -> Option AQuick Check:
Context uses req.user = context: ({ req }) => ({ user: req.user }) [OK]
- Using res instead of req
- Passing user as argument instead of req
- Setting static user instead of dynamic
context.user is { id: 5, role: 'admin' }?
resolve(parent, args, context) {
if (context.user?.role === 'admin') {
return 'Access granted';
} else {
return 'Access denied';
}
}Solution
Step 1: Check user role in context
The code checks if context.user.role equals 'admin'. Given context.user.role is 'admin', condition is true.Step 2: Determine returned string
Since condition is true, the resolver returns 'Access granted'.Final Answer:
'Access granted' -> Option CQuick Check:
context.user.role === 'admin' -> 'Access granted' [OK]
- Ignoring optional chaining and assuming error
- Confusing role values
- Assuming null return
const server = new ApolloServer({
typeDefs,
resolvers,
context: (req) => {
const user = authenticate(req.headers.authorization);
return { user };
}
});Solution
Step 1: Check context function parameter
ApolloServer passes an object with req property, so context should destructure it as ({ req }).Step 2: Identify correct usage of authorization header
Authorization header is accessed via req.headers.authorization, so destructuring is needed.Final Answer:
The context function should destructure req as ({ req }) -> Option AQuick Check:
Context param = ({ req }) not (req) [OK]
- Using req directly without destructuring
- Assuming authenticate is missing error
- Returning user instead of object
resolve(parent, args, context) {
// args.id is the data owner ID
// context.user has id and role
???
}Solution
Step 1: Understand access rules
Access is allowed if user owns data (user.id === args.id) or user is admin (role === 'admin').Step 2: Check condition logic
if (context.user.id === args.id || context.user.role === 'admin') { return 'Allowed'; } else { return 'Denied'; } correctly uses OR (||) to allow access if either condition is true.Final Answer:
if (context.user.id === args.id || context.user.role === 'admin') { return 'Allowed'; } else { return 'Denied'; } -> Option DQuick Check:
Owner or admin -> allow access [OK]
- Using AND instead of OR
- Denying admins access
- Ignoring user ID check
Ready to prove it?
Pass the test and this pattern moves unknown
