Edit on GitHub

Role-Based Authorization

This guide explains how to implement role-based access control (RBAC) in your SvelteKit application using Svelte Guardian.

Understanding Roles in Svelte Guardian

Role-based authorization allows you to control what users can access based on their assigned roles. Common examples include:

  • Admin: Full access to all features
  • Editor: Can create and edit content
  • Moderator: Can review and approve content
  • User: Standard access to protected features
  • Guest: Limited access to public features

Setting Up User Roles

1. Database Schema

Svelte Guardian includes a role field in the default User model. When using Prisma, your schema might look like:

model User { id String @id @default(cuid()) name String? email String? @unique emailVerified DateTime? password String? image String? role String? @default("user") // Role field accounts Account[] sessions Session[] }

For more complex permission systems, you might create separate models:

model Role { id String @id @default(cuid()) name String @unique description String? users User[] permissions Permission[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Permission { id String @id @default(cuid()) name String @unique description String? roles Role[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model User { // Other fields... roles Role[] }

2. Including Role in Session

Roles are included in the session by defailt. Simply ensure you use yge role field, or spefify your rolefiel name in roleKey config

Protecting Routes Based on Roles

1. Server-Side Route Protection

Configure route protection in your Svelte Guardian setup:

// src/hooks.server.ts const { handle } = await guardianAuth({ // Other config... security: { routeProtection: { protectedRoutes: { '/admin': { allowedRoles: ['admin'], redirectPath: '/unauthorized' }, '/editor': { allowedRoles: ['admin', 'editor'], redirectPath: '/unauthorized' }, '/dashboard': { authenticated: true, // Any authenticated user redirectPath: '/signin' } } } } });

2. Page-Level Role Checks

In your SvelteKit pages, you can check roles in +page.server.ts files:

// src/routes/admin/+page.server.ts import { redirect } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; export const load: PageServerLoad = async ({ locals }) => { const session = await locals.getSession(); if (!session?.user) { redirect(302, '/signin'); } if (session.user.role !== 'admin') { redirect(302, '/unauthorized'); } // Admin-specific data loading const adminData = await getAdminData(); return { adminData }; };

Role-Based UI Elements

1. Conditional UI in Svelte Components

Make UI elements appear based on the user’s role:

2. Creating Reusable Role Guards

Create reusable components to handle role-based UI protection:

{#if hasAccess} {:else if showError}
You don't have permission to access this content.
{/if}

//TODO Add this component to library

Using the guard component:

Content Management

This section requires editor privileges.

Request Access

Advanced Role-Based Features

1. Custom Authorization Logic

For complex permission rules, you can use custom authorization functions(Not yet implemented):

const { handle } = await guardianAuth({ security: { routeProtection: { protectedRoutes: { '/projects/:projectId': { authorize: async ({ user, params, request }) => { // Check if the user has access to the specific project if (!user) return false; // For admins, allow all access if (user.role === 'admin') return true; // For others, check project membership const projectId = params.projectId; const hasAccess = await checkProjectAccess(user.id, projectId); return hasAccess; }, redirectPath: '/unauthorized' } } } } });

2. Permission-Based Authorization

For more granular control, implement a permission system: //TODO

// src/lib/permissions.ts export const PERMISSIONS = { USER_CREATE: 'user:create', USER_UPDATE: 'user:update', USER_DELETE: 'user:delete', POST_CREATE: 'post:create', POST_UPDATE: 'post:update', POST_DELETE: 'post:delete', SETTINGS_UPDATE: 'settings:update' }; export const ROLE_PERMISSIONS = { admin: Object.values(PERMISSIONS), editor: [ PERMISSIONS.POST_CREATE, PERMISSIONS.POST_UPDATE, PERMISSIONS.POST_DELETE ], user: [] }; export function hasPermission(user, permission) { if (!user) return false; const userPermissions = ROLE_PERMISSIONS[user.role] || []; return userPermissions.includes(permission); }

Use in components:

{#if canCreatePost} {/if} {#if canDeletePost} {/if}

Best Practices

  1. Defense in Depth: Never rely only on UI hiding - always enforce role checks on the server
  2. Principle of Least Privilege: Assign users the minimum roles they need
  3. Role Auditing: Log role changes for security tracking
  4. Regular Role Review: Periodically review and update role assignments
  5. Clear Role Definitions: Clearly document what each role can and cannot do
  6. Role Inheritance: Design roles to inherit permissions from less privileged roles
  7. Separation of Concerns: Separate role checking logic from business logic

Next Steps

Share this page