GraphQL User & Authentication

PagibleAI uses your Laravel application’s default authentication guard. The GraphQL login mutation starts a session for an existing user; CMS permissions decide which queries and mutations that user may run.

Start with the PagibleAI GraphQL API guide for the request headers, JSON scalar rule and complete curl setup. This page focuses on the authentication lifecycle and CMS-specific user fields.

Grant editor access

Grant the CMS editor role from the project directory. If the user doesn't exist yet, the command asks for a password and creates it:

php artisan cms:user --role=editor editor@example.com

Remove all CMS roles and permissions when the account should no longer access the CMS:

php artisan cms:user --disable editor@example.com

Use --role=publisher or --role=admin for other roles, --add and --remove for individual permissions, --list to show the user’s permissions and --roles to list all roles. See Authorization & Permissions for details.

Log in

cmsLogin accepts the user’s email address and password and returns the application’s User type. In a browser client, retain the session cookie by sending requests with credentials: "include".

mutation Login($email: String!, $password: String!) {
  cmsLogin(email: $email, password: $password) {
    id
    name
    email
  }
}
{
  "email": "editor@example.com",
  "password": "secret"
}

Repeated failed logins are rate-limited. Treat credentials as secrets and use HTTPS outside local development.

Login error response

{
  "errors": [
    {
      "message": "Invalid credentials",
      "path": ["cmsLogin"]
    }
  ],
  "data": null
}

Three failed attempts for the same email address and IP trigger a 60-second lockout. Independently, the cms-login rate limiter allows at most 10 login requests per minute per IP. Do not distinguish unknown users from incorrect passwords in your client messages.

Read the current CMS user

Use me after authentication. Unlike the application’s normal User type, CmsUser includes resolved CMS permissions, named roles and editor preferences.

query CurrentCmsUser {
  me {
    id
    name
    email
    permission
    roles
    settings
  }
}
{
  "data": {
    "me": {
      "id": "42",
      "name": "CMS editor",
      "email": "editor@example.com",
      "permission": "{\"page:view\":true,\"page:add\":true,\"page:save\":true}",
      "roles": [
        "editor"
      ],
      "settings": "{\"lang\":\"en\",\"theme\":\"dark\"}"
    }
  }
}

permission contains the resolved capabilities after expanding roles, wildcards and ! exclusions. roles lists only the named roles assigned to the user, not individual permission entries.

CmsUser fields

Field
Type
Meaning
id
ID!
Application user identifier
name
String!
Display name
email
String!
Email address
permission
JSON!
JSON-encoded resolved capabilities keyed by action
roles
[String!]!
Named CMS roles assigned to the user
settings
JSON
JSON-encoded editor preferences, or null

Update editor preferences

setUser stores the JSON document you provide in the authenticated user’s CMS settings. Because the MLL JSON scalar expects a JSON-encoded string, stringify the settings object once in your variables. The mutation returns the application User, so query me afterwards when you want to read the CMS-specific settings field.

mutation SavePreferences($settings: JSON!) {
  setUser(settings: $settings) {
    id
    name
    email
  }
}
{
  "settings": "{\"lang\":\"de\",\"theme\":\"dark\",\"page\":{\"filter\":{\"view\":\"list\"}}}"
}

After the mutation succeeds, run CurrentCmsUser again and parse me.settings to confirm the stored preferences. setUser deliberately returns the application User, so selecting settings, roles or permission directly from its result is invalid.

The encoded settings document is limited to 64 KB. permission and settings are returned as JSON-encoded strings, so parse them before use. Do not store credentials or access tokens in this field.

Manage users and access

Administrators can look up users and change their CMS assignments through GraphQL. These operations are scoped to the current tenant. The user operations require the matching user:* permissions and the access catalog operations the matching access:* permissions, which only the admin role has by default. The access query is also available to callers with page:access, which the publisher role includes. Users can never change their own permissions.

User administration operations

Operation
Permission
Purpose
cmsUser(email) query
user:access or user:permission
Find a user by exact email address; returns id, email, access (needs user:access) and permissions (needs user:permission), or null
permissions query
user:permission
List the configured role names and registered permission names
access(term, first) query
access:view or page:access
List the available frontend access values
createUser(email)
user:create
Create a tenant user with random credentials and no assignments
setUserAccess(id, access)
user:access
Replace the user’s directly assigned frontend access values (max. 250)
setUserPermissions(id, permissions)
user:permission
Replace the user’s raw roles and permissions (max. 250)
addAccess(value) / deleteAccess(values)
access:add / access:delete
Add or remove values from the frontend access catalog
query FindUser($email: String!) {
  cmsUser(email: $email) {
    id
    email
    access
    permissions
  }
}

mutation GrantPublisher($id: ID!) {
  setUserPermissions(id: $id, permissions: ["publisher", "!page:purge"])
}

Log out

cmsLogout ends the authenticated session, invalidates its session data and rotates the CSRF token.

After logout, discard cached user data and obtain a fresh session and CSRF token before the next login attempt.

mutation Logout {
  cmsLogout {
    id
    name
    email
  }
}

Permission errors

Authentication only identifies the user. Each protected field also checks the relevant CMS capability, such as page:view or file:save. A logged-in user without that capability receives a GraphQL error. Check the top-level errors array and do not assume login grants full CMS access.

{
  "errors": [
    {
      "message": "Insufficient permissions",
      "path": ["pages"]
    }
  ],
  "data": {
    "pages": null
  }
}

Authentication troubleshooting

Common authentication problems

Symptom
Cause
Resolution
HTTP 419
Missing or stale CSRF token
Refresh the session and resend the decoded XSRF cookie as a header
Invalid credentials
Email or password was rejected
Check the account without exposing which credential failed
Too many login attempts
Three failures for the email and IP, or more than 10 login requests per minute from the IP
Wait at least 60 seconds before retrying
Unauthenticated
The session cookie is absent or expired
Send credentials with the request and log in again
Insufficient permissions
The user is authenticated but lacks a CMS capability
Inspect parsed me.permission and update the assigned role
You cannot change your own permissions
setUserPermissions was called for the logged-in user
Let another administrator change the assignments
Cannot query field on User
A CMS-only field was selected from setUser or cmsLogin
Request permission, roles and settings through me