v15 Stable Authentication, Session & User Roles
Frappe Framework v15 manages active user sessions, role-based access control (RBAC), and instance-level User Permissions across both Python backend and JavaScript client environments.
1. Active Session Context (frappe.session)
The frappe.session object contains metadata regarding the current authenticated user making an HTTP request or executing server code.
Python Backend frappe.session Reference
| Attribute | Return Type | Description & Value Example |
|---|---|---|
frappe.session.user | str | Active user ID email (e.g., 'john@example.com' or 'Guest') |
frappe.session.sid | str | Active HTTP session cookie ID hash |
frappe.session.data | dict | Session data dict containing user_type, language, session_ip |
frappe.session.user_type | str | User classification ('System User' or 'Website User') |
import frappe
@frappe.whitelist()
def get_current_user_profile():
# 1. Identify active session user
current_user = frappe.session.user
if current_user == "Guest":
frappe.throw("Authentication required to access user profile.", frappe.AuthenticationError)
# 2. Access session SID and data
session_id = frappe.session.sid
user_type = frappe.session.data.user_type
return {
"user": current_user,
"user_type": user_type,
"roles": frappe.get_roles(current_user)
}Client-Side JavaScript frappe.session & frappe.user
On the browser client Desk interface, session details are exposed globally:
| Client Attribute | Return Type | Description & Example |
|---|---|---|
frappe.session.user | string | Email string of logged-in user ("admin@example.com") |
frappe.session.user_fullname | string | Display full name string ("Administrator") |
frappe.user_roles | Array | List array of role strings assigned to user |
frappe.ui.form.on("Task", {
refresh(frm) {
// 1. Get current logged-in user email
let current_user = frappe.session.user;
// 2. Check if user is Guest
if (current_user === "Guest") {
frappe.show_alert({ message: __("Please log in"), indicator: "orange" });
}
// 3. Inspect user full name
console.log("Logged in as:", frappe.session.user_fullname);
}
});2. User Roles API (get_roles & has_role)
Roles determine permission capabilities across DocTypes.
Server-Side Python Role APIs
import frappe
# 1. Get all roles assigned to current session user (or target user)
user_roles = frappe.get_roles(frappe.session.user)
# Returns: ['System Manager', 'Projects User', 'All', 'Guest']
# 2. Check if user possesses specific role
is_manager = frappe.has_role("System Manager", user=frappe.session.user)
if not is_manager:
frappe.throw("Access denied: Requires System Manager role.")Client-Side JavaScript Role Inspection (frappe.user.has_role)
frappe.ui.form.on("Task", {
refresh(frm) {
// 1. Check if client user has specific role
if (frappe.user.has_role("System Manager")) {
frm.add_custom_button(__("Admin Settings"), () => {
frappe.set_route("Form", "System Settings");
});
}
// 2. Inspect all roles assigned to current user
if (frappe.user_roles.includes("Projects Manager")) {
frm.set_df_property("priority", "read_only", 0);
}
}
});3. Session User Permissions (get_user_permissions)
User Permissions constrain users to specific record instances (e.g. User john@company.com is restricted to Company: Acme North).
Fetching & Evaluating User Permissions (Python)
import frappe
from frappe.permissions import get_user_permissions, has_permission
# 1. Fetch dictionary of all User Permissions assigned to active user
user_perms = get_user_permissions(user=frappe.session.user)
# Returns: {'Company': [{'doc': 'Acme North'}], 'Territory': [{'doc': 'North America'}]}
# 2. Programmatically evaluate document permission
can_read = has_permission("Sales Invoice", ptype="read", doc="SINV-00001", user=frappe.session.user)
can_write = has_permission("Sales Invoice", ptype="write", doc="SINV-00001")
if not can_write:
frappe.throw("You do not have write permission for this invoice.")Client-Side User Defaults & Permissions (JavaScript)
// 1. Get user default setting (e.g. default Company or Fiscal Year)
let default_company = frappe.defaults.get_user_default("Company");
// 2. Get user permission restrictions object
let user_permissions = frappe.defaults.get_user_permissions();
if (user_permissions && user_permissions.Company) {
console.log("Allowed Companies:", user_permissions.Company.map(d => d.doc));
}4. Programmatic Permission Hooks
has_permission Hook
Evaluates custom Python logic to grant or deny access to a specific document instance.
# hooks.py
has_permission = {
"Task": "my_custom_app.permissions.check_task_access"
}# my_custom_app/permissions.py
import frappe
def check_task_access(doc, ptype="read", user=None):
if not user:
user = frappe.session.user
# System Managers always have access
if "System Manager" in frappe.get_roles(user):
return True
# Restrict read/write to task owner or allocated user
if ptype in ["read", "write"]:
if doc.owner == user or doc.allocated_to == user:
return True
return False
return Truepermission_query_conditions Hook
Injects dynamic SQL WHERE clauses into all frappe.get_list and Desk ListView database queries.
# hooks.py
permission_query_conditions = {
"Task": "my_custom_app.permissions.get_task_query_conditions"
}def get_task_query_conditions(user=None):
if not user:
user = frappe.session.user
if "System Manager" in frappe.get_roles(user):
return ""
# Inject SQL condition ensuring users only see their own tasks
return f"`tabTask`.owner = {frappe.db.escape(user)} OR `tabTask`.allocated_to = {frappe.db.escape(user)}"5. Document Sharing API (frappe.share)
The Document Sharing API allows programmatically sharing specific document instances with users who otherwise would not have role-based read/write access.
import frappe
# 1. Share document with specific user
frappe.share.add(
doctype="Task",
name="TASK-2026-00001",
user="colleague@company.com",
read=1,
write=1,
share=0,
notify=1
)
# 2. Get list of users a document is shared with
shared_users = frappe.share.get_users("Task", "TASK-2026-00001")
print("Shared With:", shared_users)
# Output:
# Shared With: ['colleague@company.com']
# 3. Remove sharing permission
frappe.share.remove("Task", "TASK-2026-00001", "colleague@company.com")6. Field-Level Permission Levels (permlevel)
Frappe allows restricting specific fields within a single DocType to distinct roles using Permission Levels (permlevel 0 through 9).
- Level 0: Default permission level assigned to all fields.
- Level 1–9: Elevated permission levels. Fields assigned
permlevel: 1(e.g.salaryordiscount_amount) require explicit Role Permission Manager entries for Level 1 read/write permissions.
7. Web Security: CSRF & CORS Configuration
- CSRF Protection: Frappe automatically injects CSRF token
X-Frappe-CSRF-Tokenheaders into form submissions and client RPC calls. - CORS Setup: Configure allowed origins in
site_config.json:
{
"allow_cors": "https://myfrontend-app.com"
}