gofr icon indicating copy to clipboard operation
gofr copied to clipboard

RBAC(Role-Based Access Control) Support

Open goginenibhavani2000 opened this issue 5 months ago • 9 comments

Problem:

GoFr lacks built-in role-based access control, forcing developers to implement custom authorization logic for each route. This leads to inconsistent security implementations and code duplication.

Goal :

Create a declarative RBAC middleware that integrates seamlessly with GoFr.

  1. JSON Configuration: Define roles and permissions declaratively
  2. Multiple Usage Patterns:
  •   app.Use(rbac.Middleware(config))  // Global
    
  •  app.GET("/admin", rbac.RequireRole("admin")(handler)) // Route-specific
    
  1. Flexible Role Extraction: Support JWT claims, sessions, and custom extractors
  2. Pattern Matching: Handle wildcards () and path patterns (/users/)
  3. Helper Functions: IsAdmin(), HasRole(), GetUserRoles()

Implementation Plan

  • [ ] Models-

// RoleConfig defines the roles and their allowed paths/permissions. type RoleConfig struct { Roles map[string][]string json:"roles" // e.g., {"admin": ["*"], "editor": ["/edit", "/update"]} }

// Options allow flexible configuration. type Options struct { RoleExtractor func(*Context) ([]string, error) // customized function can be passed Config RoleConfig }

  • [ ] func to load RoleConfig (LoadRoleConfig(path string) (rbac.RoleConfig, error)) and validate config
  • [ ] Implement func Middleware(opt Options) http.Handler for global use
  • [ ] Implement route-specific like RequireRole(role string) http.Handler
  • [ ] isAuthorized function should support pattern match(match(pattern, path string) bool) for wildcard and prefix matching
  • [ ] Implement helper functions: IsAdmin(c *Context) bool , HasRole(c *Context, role string), GetUserRoles(c *Context) ([]string, error)

goginenibhavani2000 avatar Jul 03 '25 15:07 goginenibhavani2000

Sure Assigning it to you. However I would need other maintainers @aryanmehrotra & @Umang01-hash, opinion on your implementation design.

coolwednesday avatar Jul 04 '25 07:07 coolwednesday

You can start working on it. Please ensure you implement an optional parameter design pattern to avoid this from becoming a breaking change.

Tag me here ! if you have any doubts.

coolwednesday avatar Jul 08 '25 07:07 coolwednesday

@coolwednesday Can you please check the draft PR for RBAC support- https://github.com/gofr-dev/gofr/pull/2049

Follow up Questions:

  1. The customized RoleExtractorFunc needs gofr.ctx as a parameter, can it be generalized or anything to be changed?
  2. What should be the default logic to extract roles for an HTTP reqquest?
  3. Can we use os.ReadFile(path) to read the json configured file of roles with permissions?

Please let me know for any further issues present in the PR or suggestions that we can discuss. Ignore the sample main.go file changes and go.mod file changes.

goginenibhavani2000 avatar Jul 11 '25 05:07 goginenibhavani2000

Hey, can you share how it would look like when the user uses, what are the things user might need to setup.

aryanmehrotra avatar Jul 11 '25 08:07 aryanmehrotra

@aryanmehrotra Please check this is how it will look like for users

Image

goginenibhavani2000 avatar Jul 14 '25 05:07 goginenibhavani2000

@goginenibhavani2000 We need tp use app.UseMiddleware(rbac.Middleware(rbacConfigs)) else it will not be applied as global middleware.

Umang01-hash avatar Jul 14 '25 10:07 Umang01-hash

@Umang01-hash I have pushed my changes to a branch, can you please check it, tested few use cases, 1 use case is not working as expected, want help on the same. Also i have raised few questions in discord discussions. Can you please look into it and confirm if my changes are as expected. Discord post link- https://discord.com/channels/1156248707931590666/1394236937824505866 my branch comparison with development- https://github.com/gofr-dev/gofr/compare/development...goginenibhavani2000:gofr:RBAC-middleware-support?expand=1

RBAC use cases tested in local:

  • Global middleware with admin in config.json and exact req path- passed
  • Global middleware with role in config.json and suffix pattern matching for path- passed
  • Global middleware with role in config.json and prefix pattern matching for path- passed
  • Overriding of Global middleware with route specific- failed- (ex- user1 role is required for /greet but that role is not present in config.json or path is not allowed via config.json file)- it fails at main middleware, to fix, we can skip global check if provided in middleware as a config
  • Using just route specific - failed- r.cloneContext(ctx) is not working with gofr.Context

goginenibhavani2000 avatar Jul 17 '25 14:07 goginenibhavani2000

@goginenibhavani2000, Please raise the PR. It is easier to compare the changes and suggest changes through that. The review process will get much more faster.

Thank you !

coolwednesday avatar Jul 31 '25 13:07 coolwednesday

@Umang01-hash @coolwednesday Please review https://github.com/gofr-dev/gofr/pull/2144

goginenibhavani2000 avatar Aug 11 '25 20:08 goginenibhavani2000