Skip to content

Feature: Support Display types for security scopes in path and openapi macros #1462

@JMLX42

Description

@JMLX42

Feature Request

Problem Statement

Currently, security scopes in #[utoipa::path] and #[openapi] macros only accept string literals:

#[utoipa::path(
    security(
        ("bearerAuth" = ["accessor:read", "accessor:write"])
    )
)]

This approach has limitations:

  • No compile-time validation of scope values
  • Prone to typos that are only caught at runtime
  • Cannot leverage Rust's type system for better organization and safety

Proposed Solution

Allow security scopes to accept any type that implements Display:

enum Scope {
    Accessor,
    Read,
}

impl Display for Scope {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // Format as needed, e.g., "accessor:read"
        write!(f, "{}:{}", self.resource().to_lowercase(), self.action().to_lowercase())
    }
}

#[utoipa::path(
    security(
        ("bearerAuth" = [Scope::Accessor(Action::Read)])
    )
)]

Benefits

  • Type Safety: Compile-time validation of security scopes
  • Better Organization: Scopes can be defined as enums/structs with clear semantics
  • IDE Support: Autocomplete and refactoring tools work better with types
  • Maintainability: Centralized scope definitions that are easier to update
  • Backwards Compatible: String literals would still work

Implementation Approach

The existing LitStrOrExpr enum in utoipa-gen/src/lib.rs can be reused for this purpose. The main changes would be:

  1. Update SecurityRequirementsAttrItem in security_requirement.rs to use LitStrOrExpr for scopes
  2. Modify parsing logic to accept both literals and expressions
  3. Update ToTokens implementation to call .to_string() on expressions

Example Use Cases

// Enum-based scopes with Display
enum Resource { User, Post, Comment }
enum Action { Read, Write, Delete }

struct Scope(Resource, Action);
impl Display for Scope { /* ... */ }

#[utoipa::path(
    security(
        ("oauth2" = [Scope(Resource::User, Action::Read)])
    )
)]

// Or simpler enum
enum SimpleScope {
    UserRead,
    UserWrite,
    AdminAll,
}
impl Display for SimpleScope { /* ... */ }

#[utoipa::path(
    security(
        ("bearerAuth" = [SimpleScope::UserRead, SimpleScope::UserWrite])
    )
)]

I'm willing to implement this feature and submit a PR if there's interest in accepting it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions