Skip to content

Grav User Management — Login Plugin, Permissions and Accounts

DodaTech Updated 2026-06-27 7 min read

In this tutorial, you'll learn Grav user management — configuring the Login plugin, creating and managing user accounts, setting permissions and access control, user groups, and building authentication workflows.

What You'll Learn

  • The Login plugin and its features
  • Creating and managing user accounts
  • User permissions and access control
  • User groups and role-based access
  • Registration, password reset, and profile management
  • Protecting pages and sections with access rules

Why It Matters

In WordPress, users and roles are built into the core with a database. In Grav, user accounts are YAML files stored in user/accounts/. Each file is a user profile with username, email, password (hashed), and permissions. The Login plugin handles authentication, registration, and password management. This file-based approach makes user management simple, transparent, and Git-friendly.

Real-World Use

A membership documentation site has three user levels: free users (access to basic docs), premium users (access to advanced guides and downloads), and admin users (full access including user management). Each user account is a YAML file with an access field. Pages check the user's access level and show or hide content accordingly. When a user upgrades, an admin edits the YAML file to change their access level — no database query, no plugin configuration.

Learning Path

flowchart LR
    A["Multilingual"] --> B["User Management
← You are here"]:::current B --> C["Media Handling"] C --> D["Grav API"] D --> E["Web Services"] E --> F["E-commerce with Grav"] F --> G["Caching Deep Dive"] classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px

Installing the Login Plugin

bin/gpm install login

The Login plugin provides:

  • User authentication with multiple providers
  • Registration and password reset
  • Profile management
  • Page access control
  • OAuth support (GitHub, Google, Facebook)

User Account Files

Each user is a YAML file in user/accounts/:

user/accounts/admin.yaml:

username: admin
email: admin@example.com
password: $2y$10$hashedpasswordhere
language: en
twofa_enabled: false
twofa_secret: ''
access:
    site:
        login: true
    admin:
        login: true
        super: true
fullname: Admin User
title: Site Administrator
state: enabled
groups:
    - admins

user/accounts/jane.yaml:

username: jane
email: jane@example.com
password: $2y$10$anotherhashedpassword
language: en
access:
    site:
        login: true
    admin:
        login: false
fullname: Jane Doe
title: Premium Member
state: enabled
groups:
    - premium

Creating Users via CLI

# Create a new admin user
bin/grav new-admin-user

# You will be prompted for:
Username: admin
Email: admin@example.com
Password: [hidden]

Creating Users Programmatically

$accounts = $this->grav['accounts'];
$user = $accounts->add([
    'username' => 'jane',
    'email' => 'jane@example.com',
    'password' => 'securepassword123',
    'fullname' => 'Jane Doe',
    'groups' => ['premium'],
    'access' => [
        'site' => ['login' => true],
    ],
]);
$accounts->save($user);

Access Control Configuration

System Permissions

In user/config/system.yaml:

home:
    alias: '/home'
    hide_in_urls: false

accounts:
    type: data
    storage: file

login:
    route: /login
    route_redirect: /
    route_after_login: /
    route_after_logout: /

Page Access Control

Restrict access to specific pages using frontmatter:

---
title: Premium Guide
access:
    site:
        login: true
        premium: true
---

Or by group:

---
title: Admin Dashboard
access:
    admin:
        login: true
        super: true
---

Section-Level Access

Use folder.md to protect an entire section:

---
# user/pages/05.premium/folder.md
title: Premium Content
access:
    site:
        premium: true
---

All child pages inherit this access requirement.

Checking Access in Templates

{% if grav.user.authorize('site.login') %}
    <p>Welcome, {{ grav.user.fullname }}!</p>
{% endif %}

{% if grav.user.authorize('site.premium') %}
    <div class="premium-content">
        {{ page.content|raw }}
    </div>
{% else %}
    <div class="upgrade-notice">
        <p>This content is for premium members only.</p>
        <a href="/upgrade">Upgrade now</a>
    </div>
{% endif %}

User Registration

Enable registration in user/config/plugins/login.yaml:

enabled: true
built_in_login: true
route: /login
route_register: /register
user_registration:
    enabled: true
    fields:
        - 'username'
        - 'fullname'
        - 'email'
        - 'password'
    access:
        site:
            login: true
    options:
        validate_password1_and_password2: true
        set_user_disabled: false
        login_after_registration: true
        send_activation_email: false
        send_notification_email: true
        welcome_email: false

Create the registration page:

---
title: Register
route: /register
---

The Login plugin automatically provides the registration form at this route.

Password Reset

Add to login.yaml:

rememberme:
    enabled: true
    lifetime: 604800  # 7 days

forgot:
    enabled: true
    route: /forgot-password
    route_reset: /reset-password

Password reset flow:

  1. User visits /forgot-password
  2. Enters email
  3. Receives email with reset link
  4. Clicks link, enters new password
  5. Password is updated

User Groups

Define groups in user/config/groups.yaml:

free:
    access:
        site:
            login: true

premium:
    access:
        site:
            login: true
            premium: true

admins:
    access:
        admin:
            login: true
            super: true
        site:
            login: true

Users inherit permissions from their groups:

if ($this->grav['user']->authorize('site.premium')) {
    // User is in the premium group or has direct premium access
}

OAuth Authentication

# user/config/plugins/login.yaml
oauth:
    enabled: true
    providers:
        github:
            enabled: true
            client_id: 'your-client-id'
            client_secret: 'your-client-secret'

        google:
            enabled: true
            client_id: 'your-google-client-id'
            client_secret: 'your-google-client-secret'

Learning Path

flowchart LR
    A["Multilingual"] --> B["User Management
← You are here"]:::current B --> C["Media Handling"] C --> D["Grav API"] D --> E["Web Services"] classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px

Common Mistakes

  1. Storing passwords in plain text: User passwords are automatically hashed by Grav. Never manually edit the password field in a user YAML file — always use bin/grav new-admin-user or the Admin panel.

  2. Not setting site.login: true in user access: Without this basic permission, even authenticated users cannot access protected pages. Every user account must have site.login: true.

  3. Forgetting group inheritance: Users inherit permissions from groups, but direct access settings override group settings. Mixing both can lead to unexpected permission results.

  4. Leaving registration open without moderation: If user_registration.enabled: true without activation email, anyone can create an account. Add set_user_disabled: true or activation email for sites with sensitive content.

  5. Not protecting admin routes: The Admin plugin's route is /admin. Ensure your server or .htaccess restricts this route to authorized IPs or use Grav's built-in admin authentication.

Practice Questions

  1. Where are Grav user accounts stored? Answer: In user/accounts/ as YAML files. Each file is one user account with username, email, password hash, and access permissions.

  2. How do you restrict a page to logged-in users only? Answer: Add access.site.login: true to the page frontmatter. Users who are not logged in are redirected to the login page.

  3. What is the purpose of user groups? Answer: Groups define a set of permissions that apply to all members. Instead of setting permissions per user, you assign users to groups and manage permissions centrally in groups.yaml.

  4. How do you check a user's permission in a Twig template? Answer: Use grav.user.authorize('permission.key'). For example, grav.user.authorize('site.premium') checks if the user has premium access.

  5. Challenge: Build a complete membership system with 3 user levels (free, premium, admin). Create user groups for each level with appropriate permissions. Create 5 premium pages that are only accessible to premium users. Create a registration form with email verification. Create a login page with "remember me" functionality. Create a password reset flow. Add a profile page where users can update their name and email. Create admin-only pages for user management. Test all flows: registration, login, access control, password reset, and profile update.

FAQ

How do I change a user's password?

Use the Admin panel or run bin/grav new-admin-user with the same username to update the password. Alternatively, edit the user YAML file — Grav hashes the password automatically on next login.

Can I use LDAP or Active Directory for authentication?

Yes. The Login plugin supports custom authentication handlers. Build a custom authentication provider in a plugin that validates against LDAP.

How do I create a user programmatically?

Use $this->grav['accounts']->add([...]) with the user fields. Call $accounts->save($user) to persist the account file.

What happens if a user YAML file is deleted?

The user account no longer exists. Anyone with that username cannot log in. User files deleted through the Admin panel or filesystem are permanent.

Can I store additional custom fields in user accounts?

Yes. Add any fields you need to the user YAML file. Access them in Twig with grav.user.CUSTOMFIELD. Ensure the Login plugin's registration form includes the new fields.

Mini Project

Goal: Build a complete membership site with tiered access.

  1. Install and configure the Login plugin
  2. Create user groups: free, premium, admin with distinct permissions
  3. Create user accounts for each group
  4. Create a registration page with custom fields (company name, phone)
  5. Create a login page with remember me functionality
  6. Create premium content pages with access control
  7. Create a profile page for users to update their information
  8. Implement a "Welcome" email on registration
  9. Create an admin-only dashboard showing all users
  10. Test all authentication and authorization flows

What's Next

Now you can manage users and access control. Next, learn media handling:

Continue to Lesson 31: Media Handling — Image manipulation, thumbnails, media aliases, and responsive images.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro