Quick Start Guide
Get up and running with perms.io's Resource-Specific RBAC system in minutes. This guide will walk you through setting up permissions and performing access checks.
Overview
perms.io provides a complete RBAC system with: - Organisations - Top-level containers for your resources - Projects - Logical groupings within organisations - Permissions - Individual actions (read, write, delete) - Roles - Collections of permissions - Principals - Users or entities that can be granted access
Prerequisites
- Account at app.perms.io
- Organization, project, and API key created via the dashboard
- Basic understanding of REST APIs or gRPC
Step 1: Setup via Dashboard
Before using the API, complete the initial setup through the web dashboard:
- Create Your Organisation: Go to app.perms.io and create your organization
- Create a Project: Create a project within your organization (e.g., "production")
- Generate API Key: Create an API key for your project to use in the examples below
Step 2: Create Permissions
Define the actions that can be performed in your application.
# Create read permission
curl -X POST "https://api.perms.io/permissions-service/v1/permissions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_name": "production",
"name": "document.read",
"description": "Allows reading documents"
}'
# Create write permission
curl -X POST "https://api.perms.io/permissions-service/v1/permissions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_name": "production",
"name": "document.write",
"description": "Allows writing documents"
}'
func createPermissions(client permissionsv1.PermissionsServiceClient, ctx context.Context) ([]string, error) {
permissions := []struct {
name string
description string
}{
{"document.read", "Allows reading documents"},
{"document.write", "Allows writing documents"},
}
var permissionIds []string
for _, perm := range permissions {
req := &permissionsv1.CreatePermissionRequest{
ProjectName: "production",
Name: perm.name,
Description: perm.description,
}
resp, err := client.CreatePermission(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to create permission %s: %v", perm.name, err)
}
permissionIds = append(permissionIds, resp.Id)
fmt.Printf("Created permission: %s (ID: %s)\n", resp.Name, resp.Id)
}
return permissionIds, nil
}
def create_permissions():
channel = grpc.secure_channel('api.perms.io:443', ssl_channel_credentials())
client = permissions_service_pb2_grpc.PermissionsServiceStub(channel)
metadata = [('authorization', 'Bearer YOUR_API_KEY')]
permissions = [
("document.read", "Allows reading documents"),
("document.write", "Allows writing documents")
]
permission_ids = []
for name, description in permissions:
request = permissions_service_pb2.CreatePermissionRequest(
project_name="production",
name=name,
description=description
)
response = client.CreatePermission(request, metadata=metadata)
permission_ids.append(response.id)
print(f"Created permission: {response.name} (ID: {response.id})")
return permission_ids
Step 3: Create Roles
Group permissions into roles for easier management.
# Create editor role
curl -X POST "https://api.perms.io/permissions-service/v1/roles" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_name": "production",
"name": "document_editor",
"description": "Can read and write documents",
"permissions": ["PERMISSION_ID_1", "PERMISSION_ID_2"]
}'
func createRoles(client permissionsv1.PermissionsServiceClient, ctx context.Context, permissionIds []string) ([]string, error) {
roles := []struct {
name string
description string
permissions []string
}{
{
name: "document_viewer",
description: "Can read documents",
permissions: []string{permissionIds[0]}, // read only
},
{
name: "document_editor",
description: "Can read and write documents",
permissions: []string{permissionIds[0], permissionIds[1]}, // read + write
},
}
var roleIds []string
for _, role := range roles {
req := &permissionsv1.CreateRoleRequest{
ProjectName: "production",
Name: role.name,
Description: role.description,
Permissions: role.permissions,
}
resp, err := client.CreateRole(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to create role %s: %v", role.name, err)
}
roleIds = append(roleIds, resp.Id)
fmt.Printf("Created role: %s (ID: %s)\n", resp.Name, resp.Id)
}
return roleIds, nil
}
def create_roles(permission_ids: list[str]) -> list[str]:
channel = grpc.secure_channel('api.perms.io:443', ssl_channel_credentials())
client = permissions_service_pb2_grpc.PermissionsServiceStub(channel)
metadata = [('authorization', 'Bearer YOUR_API_KEY')]
roles = [
("document_viewer", "Can read documents", [permission_ids[0]]),
("document_editor", "Can read and write documents", [permission_ids[0], permission_ids[1]]),
]
role_ids = []
for name, description, permissions in roles:
request = permissions_service_pb2.CreateRoleRequest(
project_name="production",
name=name,
description=description,
permissions=permissions
)
response = client.CreateRole(request, metadata=metadata)
role_ids.append(response.id)
print(f"Created role: {response.name} (ID: {response.id})")
return role_ids
Step 4: Grant Permissions to Users
Assign permissions and roles to users on specific resources.
# Grant editor role to user on specific document
curl -X POST "https://api.perms.io/permissions-service/v1/permissions/assign" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_name": "production",
"user_id": "user_123",
"resource_uri": "/documents/doc_456",
"permissions": [],
"roles": ["ROLE_ID"]
}'
func grantPermissions(client permissionsv1.PermissionsServiceClient, ctx context.Context, roleIds []string) error {
req := &permissionsv1.GrantUserPermissionsAndRolesOnResourceRequest{
ProjectName: "production",
UserId: "user_123",
ResourceUri: "/documents",
Permissions: []string{},
Roles: []string{roleIds[0]}, // viewer role
}
_, err := client.GrantUserPermissionsAndRolesOnResource(ctx, req)
if err != nil {
return fmt.Errorf("failed to grant permissions: %v", err)
}
fmt.Printf("Granted permissions to user_123 on /documents\n")
return nil
}
def grant_permissions(role_ids: list[str]):
channel = grpc.secure_channel('api.perms.io:443', ssl_channel_credentials())
client = permissions_service_pb2_grpc.PermissionsServiceStub(channel)
metadata = [('authorization', 'Bearer YOUR_API_KEY')]
request = permissions_service_pb2.GrantUserPermissionsAndRolesOnResourceRequest(
project_name="production",
user_id="user_123",
resource_uri="/documents",
permissions=[],
roles=[role_ids[0]] # viewer role
)
client.GrantUserPermissionsAndRolesOnResource(request, metadata=metadata)
print("Granted permissions to user_123 on /documents")
Step 5: Check Permissions
Verify that users have the required permissions for specific actions.
# Check if user can read document
curl -X POST "https://api.perms.io/permissions-service/v1/permissions/check" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_name": "production",
"principal_id": "user_123",
"resource_uris": ["/documents/doc_456"],
"permissions": ["document.read"]
}'
func checkPermissions(client permissionsv1.PermissionsServiceClient, ctx context.Context) error {
req := &permissionsv1.CheckPermissionRequest{
ProjectName: "production",
PrincipalId: "user_123",
ResourceUris: []string{"/documents/doc_456"},
Permissions: []string{"document.read"},
}
resp, err := client.Check(ctx, req)
if err != nil {
return fmt.Errorf("failed to check permissions: %v", err)
}
if resp.Passed {
fmt.Printf("✅ User user_123 has required permissions\n")
} else {
fmt.Printf("❌ User user_123 missing permissions:\n")
for _, missing := range resp.MissingPermissions {
fmt.Printf(" Resource: %s, Missing: %v\n", missing.ResourceUri, missing.MissingPermissions)
}
}
return nil
}
def check_permissions():
channel = grpc.secure_channel('api.perms.io:443', ssl_channel_credentials())
client = permissions_service_pb2_grpc.PermissionsServiceStub(channel)
metadata = [('authorization', 'Bearer YOUR_API_KEY')]
request = permissions_service_pb2.CheckPermissionRequest(
project_name="production",
principal_id="user_123",
resource_uris=["/documents/doc_456"],
permissions=["document.read"]
)
response = client.Check(request, metadata=metadata)
if response.passed:
print("✅ User user_123 has required permissions")
else:
print("❌ User user_123 missing permissions:")
for missing in response.missing_permissions:
print(f" Resource: {missing.resource_uri}, Missing: {missing.missing_permissions}")
Complete Example
Here's a complete example that sets up a basic document management system:
# 1. Create permissions
curl -X POST "https://api.perms.io/permissions-service/v1/permissions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"project_name": "production", "name": "document.read", "description": "Read documents"}'
curl -X POST "https://api.perms.io/permissions-service/v1/permissions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"project_name": "production", "name": "document.write", "description": "Write documents"}'
# 2. Create role
curl -X POST "https://api.perms.io/permissions-service/v1/roles" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"project_name": "production", "name": "document_editor", "description": "Can read and write", "permissions": ["PERM_ID_1", "PERM_ID_2"]}'
# 3. Grant permissions
curl -X POST "https://api.perms.io/permissions-service/v1/permissions/assign" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"project_name": "production", "user_id": "user_123", "resource_uri": "/documents", "roles": ["ROLE_ID"]}'
# 4. Check permissions
curl -X POST "https://api.perms.io/permissions-service/v1/permissions/check" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"project_name": "production", "principal_id": "user_123", "resource_uris": ["/documents/doc_456"], "permissions": ["document.read"]}'
package main
import (
"context"
"fmt"
"log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
permissionsv1 "github.com/PrivateJAR/permio-go/proto/permissions/v1"
)
func main() {
// Connect to the API
conn, err := grpc.Dial("api.perms.io:443", grpc.WithTransportCredentials(credentials.NewTLS(nil)))
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()
client := permissionsv1.NewPermissionsServiceClient(conn)
// Setup authentication context
ctx := metadata.AppendToOutgoingContext(context.Background(), "authorization", "Bearer YOUR_API_KEY")
// 1. Create permissions
permissionIds, err := createPermissions(client, ctx)
if err != nil {
log.Fatalf("Failed to create permissions: %v", err)
}
// 2. Create roles
roleIds, err := createRoles(client, ctx, permissionIds)
if err != nil {
log.Fatalf("Failed to create roles: %v", err)
}
// 3. Grant permissions
err = grantPermissions(client, ctx, roleIds)
if err != nil {
log.Fatalf("Failed to grant permissions: %v", err)
}
// 4. Check permissions
err = checkPermissions(client, ctx)
if err != nil {
log.Fatalf("Failed to check permissions: %v", err)
}
fmt.Printf("Setup complete! Your RBAC system is ready to use.\n")
}
import grpc
from grpc import ssl_channel_credentials
from proto.permissions.v1 import permissions_service_pb2
from proto.permissions.v1 import permissions_service_pb2_grpc
def main():
# 1. Create permissions
permission_ids = create_permissions()
# 2. Create roles
role_ids = create_roles(permission_ids)
# 3. Grant permissions
grant_permissions(role_ids)
# 4. Check permissions
check_permissions()
print("Setup complete! Your RBAC system is ready to use.")
if __name__ == "__main__":
main()
Next Steps
Now that you have a working RBAC system, you can:
- Integrate with your application - Add permission checks to your application endpoints
- Create more complex hierarchies - Use nested resource URIs for fine-grained control
- Add more users - Invite team members to your organisation via the dashboard
- Monitor usage - Check the dashboard for usage statistics
- Implement caching - Cache permission results for better performance
Common Patterns
Multi-tenant Applications
# Tenant-specific resources
curl -X POST "https://api.perms.io/permissions-service/v1/permissions/check" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_name": "production",
"principal_id": "user_123",
"resource_uris": ["/tenant/456/projects/789"],
"permissions": ["project.read"]
}'
// Tenant-specific resources
resourceUri := fmt.Sprintf("/tenant/%s/projects/%s", tenantId, projectId)
// Check tenant access
checkResp, err := permClient.Check(ctx, &permissionsv1.CheckPermissionRequest{
ProjectName: "production",
PrincipalId: userId,
ResourceUris: []string{resourceUri},
Permissions: []string{"project.read"},
})
Hierarchical Permissions
# Grant permissions at different levels
# Organisation level
curl -X POST "https://api.perms.io/permissions-service/v1/permissions/assign" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"project_name": "production", "user_id": "user_123", "resource_uri": "/organisation/123", "permissions": ["org.admin"]}'
# Project level
curl -X POST "https://api.perms.io/permissions-service/v1/permissions/assign" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"project_name": "production", "user_id": "user_123", "resource_uri": "/organisation/123/project/456", "permissions": ["project.manage"]}'
// Grant permissions at different levels
// Organisation level
grantPermissions(userId, "/organisation/123", []string{"org.admin"}, []string{})
// Project level
grantPermissions(userId, "/organisation/123/project/456", []string{"project.manage"}, []string{})
// Resource level
grantPermissions(userId, "/organisation/123/project/456/document/789", []string{"document.edit"}, []string{})
Troubleshooting
Common Issues
- Permission Denied: Check that you have the required permissions for the operation
- Resource Not Found: Verify the resource URIs are correct
- Authentication Failed: Ensure your API key is valid
- Rate Limiting: Implement exponential backoff for API calls
Getting Help
- Check the API Reference for detailed endpoint documentation
- Visit app.perms.io for the web dashboard
- Review the IAM Fundamentals guide for RBAC concepts
You're now ready to implement fine-grained access control in your applications with perms.io!