Grav User Management — Login Plugin, Permissions and Accounts
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:
- User visits
/forgot-password - Enters email
- Receives email with reset link
- Clicks link, enters new password
- 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
Storing passwords in plain text: User passwords are automatically hashed by Grav. Never manually edit the
passwordfield in a user YAML file — always usebin/grav new-admin-useror the Admin panel.Not setting
site.login: truein user access: Without this basic permission, even authenticated users cannot access protected pages. Every user account must havesite.login: true.Forgetting group inheritance: Users inherit permissions from groups, but direct access settings override group settings. Mixing both can lead to unexpected permission results.
Leaving registration open without moderation: If
user_registration.enabled: truewithout activation email, anyone can create an account. Addset_user_disabled: trueor activation email for sites with sensitive content.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
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.How do you restrict a page to logged-in users only? Answer: Add
access.site.login: trueto the page frontmatter. Users who are not logged in are redirected to the login page.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.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.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
Mini Project
Goal: Build a complete membership site with tiered access.
- Install and configure the Login plugin
- Create user groups: free, premium, admin with distinct permissions
- Create user accounts for each group
- Create a registration page with custom fields (company name, phone)
- Create a login page with remember me functionality
- Create premium content pages with access control
- Create a profile page for users to update their information
- Implement a "Welcome" email on registration
- Create an admin-only dashboard showing all users
- 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