Understanding Authentication: Using the Customer Token, Checking the Customer Context in the Resolver
Understanding Authentication: Using the Customer Token, Checking the Customer Context in the Resolver
~8 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026
Before chapter 18 secures the favorites mutation, this chapter clarifies the fundamentals: how does a customer even log in with GraphQL, and how does a resolver recognize who's asking? As a practical, low-risk example, a new field is_favorite on the Event type serves the purpose - it can only be meaningfully filled for logged-in customers.
Generating the customer token
Magento authenticates GraphQL requests using the same token system as the REST API: a mutation generateCustomerToken from Magento_CustomerGraphQl accepts an email and password and returns a bearer token.
mutation {
generateCustomerToken(email: "customer@example.com", password: "secret123") {
token
}
}This token then travels in the Authorization header on every subsequent request:
curl -s https://mironsoft.test/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"query": "{ customer { email } }"}'How the context comes from it
Magento's GraphQL controller reads the Authorization header before any resolver runs, validates the token, and builds the ContextInterface instance from it that every resolver receives as its second parameter (chapter 10). A missing or invalid token does not automatically cause an error - the request simply continues as a guest, unless a specific field itself demands authentication.
Example: an is_favorite field with a context check
extend type Event {
is_favorite: Boolean!
@resolver(class: "Mironsoft\\Event\\Model\\Resolver\\IsFavorite")
@doc(description: "Whether the current customer has favorited this event")
}<?php
declare(strict_types=1);
namespace Mironsoft\Event\Model\Resolver;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Mironsoft\Event\Api\Data\EventInterface;
use Mironsoft\Event\Model\ResourceModel\EventFavorite;
/**
* Resolves the is_favorite field on the Event type. Always false for guests.
*/
class IsFavorite implements ResolverInterface
{
/**
* @param EventFavorite $eventFavoriteResource Resource model for the favorites linkage table
*/
public function __construct(
private readonly EventFavorite $eventFavoriteResource,
) {
}
/**
* Checks whether the current customer has favorited the resolved event.
*
* @param Field $field Resolved GraphQL field configuration
* @param mixed $context Resolver context, carries the customer ID/type
* @param ResolveInfo $info GraphQL resolve tree info
* @param array|null $value Parent Event resolver's value
* @param array|null $args Arguments passed to this field
* @return bool
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
?array $value = null,
?array $args = null
): bool {
/** @var EventInterface|null $event */
$event = $value['model'] ?? null;
if ($event === null || !$context->getExtensionAttributes()->getIsCustomer()) {
return false;
}
return $this->eventFavoriteResource->isFavorite(
(int) $context->getUserId(),
(int) $event->getEventId()
);
}
}getExtensionAttributes()->getIsCustomer() is the most reliable way to tell real customers apart from guests - more reliable than a plain getUserId() > 0 check, because getIsCustomer() is set consistently by the GraphQL framework itself based on the validated token. For guests, the field simply returns false instead of throwing an error - after all, is_favorite is a legitimately true value for guests too ("no, not favorited").
The USER_TYPE_* constants at a glance
UserContextInterface::USER_TYPE_GUEST- no authentication, no token or an expired/invalid token.UserContextInterface::USER_TYPE_CUSTOMER- a valid customer token, the case relevant foraddEventToFavorites.UserContextInterface::USER_TYPE_ADMIN- an admin token instead of a customer token, relevant for chapter 23 (ACL).UserContextInterface::USER_TYPE_INTEGRATION- an integration (comparable to a third-party app's REST access token).
Tipp: For quick, repeated testing during development, it's worth generating the token once and storing it as an environment variable or in the GraphQL client's collection - customer tokens are valid for a while by default, so logging in again for every single test call isn't necessary.
With an understanding of how the token, context, and getIsCustomer() work together, chapter 18 uses exactly this knowledge to upgrade the favorites mutation from chapter 16 into a genuinely protected mutation.