Role-based Security: Roles, Accessible By, CheckRole, GrantRole, Anonymous
Key Takeaways
- The Registered role is automatically assigned to every authenticated user; anonymous users have no roles.
- The Accessible By property on Screens controls access: All (including anonymous), Registered (logged-in), or specific Roles.
- CheckRole(RoleName) is a built-in function returning True if the current user has the specified role, used in If widgets and Server Actions for granular control.
- GrantRole and RevokeRole are Server Actions that assign or remove roles at runtime; they cannot be called directly from Client Actions.
- GetUserId() returns NullIdentifier() (0) for anonymous users, providing a way to check login status inside logic flows.
Quick Answer: OutSystems security is role-based. Roles are defined per module and assigned to users through the Users app or programmatically via GrantRole. Every Screen and Block has an Accessible By property controlling who can see it: All (including anonymous), Registered (logged-in), or specific Roles. The CheckRole built-in function tests roles inside logic flows, and the special Registered role is auto-assigned to every authenticated user.
Roles and the Registered Role
A Role in OutSystems represents a user privilege or persona (e.g., Admin, Manager, Customer). Roles are created in Service Studio at the module level, but once published they become available app-wide and are assigned to individual users through the Users application or programmatically. Every authenticated user automatically has the built-in Registered role — this is how you distinguish logged-in users from anonymous visitors without defining a custom role for it.
| Role Type | Who Has It | How Assigned |
|---|---|---|
| Registered | Every logged-in user | Automatic on authentication |
| Custom (e.g., Admin) | Specific users | Users app, GrantRole action, or SSO role mapping |
| (none) | Anonymous / not logged in | N/A — no roles assigned |
Roles are boolean per user: a user either has a role or does not. There is no hierarchy or inheritance — if Manager should include everything Employee can do, the user must be granted both roles, or the Screen's Accessible By must list both. This flat model keeps security explicit and auditable.
Accessible By Property
The Accessible By property on Screens (and Blocks) is the primary UI-level security gate. It controls who can navigate to the Screen or render the Block.
| Accessible By Value | Who Can Access | Use Case |
|---|---|---|
| All | Anyone, including anonymous | Login screen, public landing pages |
| Registered | Any logged-in user | User dashboard, account settings |
| Specific Role(s) | Only users with that role | Admin panel, manager-only reports |
When Accessible By is set to a specific role and a user without that role tries to navigate to the Screen, OutSystems redirects them to the login page (if anonymous) or shows a not-authorized message (if logged in but lacking the role). In Reactive Web Apps, this check happens at runtime on both the client and the server — the server enforces it for Data Actions and Aggregates, so a malicious client cannot bypass it by manipulating the URL or client state.
A user logs in successfully to an OutSystems Reactive Web App. Which role do they automatically receive?
CheckRole Function
The CheckRole built-in function tests whether the current user has a specific role at runtime. It returns True or False and is available in both Client Actions (for conditional UI rendering) and Server Actions (for conditional logic). For example, to show a Delete button only to managers, you wrap it in an If widget with the condition CheckRole(ManagerRole). To gate a Server Action, you add an If node with CheckRole(AdminRole) and raise an exception if false.
A key distinction: Accessible By is a declarative, compile-time property that blocks navigation entirely. CheckRole is an imperative, runtime check used inside logic to conditionally show, hide, or execute. Use Accessible By for whole-screen access control; use CheckRole for granular element-level or logic-level control within an already accessible screen.
GrantRole and RevokeRole
Roles can be assigned or removed at runtime using the GrantRole and RevokeRole server actions. These take a user identifier and a role identifier. Typical scenarios include a self-registration flow that grants the Customer role after email verification, an admin screen that lets a manager grant Editor to another user, or a deactivation workflow that revokes all roles when a user leaves.
GrantRole and RevokeRole are Server Actions only — they execute on the server and write to the platform security tables. They cannot be called directly from Client Actions; you must wrap them in a Server Action that the Client Action invokes.
Anonymous Access
When Accessible By is set to All, anonymous (not-logged-in) users can access the Screen. This is required for login and registration screens — users must reach these before they have a session — and for public content such as marketing pages or public dashboards. To check whether the current user is anonymous in logic, use GetUserId(). For anonymous users it returns NullIdentifier() (0). For logged-in users it returns a positive integer. You can also use CheckRole(RegisteredRole) — anonymous users do not have the Registered role, so it returns False.
Security on Processes and UI Elements
Beyond Screens, role-based security extends to BPT Human Activities. Each Human Activity has an Accessible By property that restricts which roles can claim and complete the activity. A process routing an approval task to Managers will only show that activity in the task inbox for users with the Manager role. Automatic activities run regardless of role — they execute as the process owner, not the current user.
Exam Traps
A frequent exam question asks what happens when Accessible By is set to a specific role but no user has been granted that role. Answer: no one can access the screen, including admins — unless an admin is separately granted that role. Another trap: CheckRole in a Client Action is evaluated on the client and could theoretically be bypassed by a determined attacker. For sensitive logic, always add a server-side CheckRole in the Server Action that performs the actual operation. The client-side check is for UX, not security.
You need to show a Delete button only to users with the Manager role on a Screen accessible to all Registered users. What is the correct approach?
Which function returns a value indicating the current user is anonymous (not logged in)?