1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//! Admin scope guard for JWT-authenticated admin requests.
//!
//! When admin routes receive a JWT (rather than a raw `admin_token`), the guard
//! verifies that the JWT's `scope` claim contains `fraiseql:admin`. Bearer-token
//! authenticated requests (using `admin_token`) bypass this check entirely for
//! backwards compatibility.
//!
//! The guard is additive: it does not replace bearer-token auth. Routes that use
//! the guard should apply it **after** the bearer-auth middleware.
/// The required scope claim value for admin API access via JWT.
pub const ADMIN_SCOPE: &str = "fraiseql:admin";
/// Check whether a space-delimited scope string contains the `fraiseql:admin` scope.
///
/// Scope claims in JWTs are typically a space-separated list of scope values
/// (RFC 8693 / `OpenID` Connect).
///
/// # Examples
///
/// ```
/// use fraiseql_server::middleware::admin_scope::has_admin_scope;
///
/// assert!(has_admin_scope("fraiseql:admin"));
/// assert!(has_admin_scope("read write fraiseql:admin"));
/// assert!(!has_admin_scope("read write"));
/// assert!(!has_admin_scope(""));
/// ```
/// Validate that a JWT scope claim authorizes admin access.
///
/// Returns `Ok(())` if the scope claim contains `fraiseql:admin`,
/// `Err` with a 403 message otherwise.
///
/// # Errors
///
/// Returns `FraiseQLError::Authorization` if the scope claim does not
/// contain `fraiseql:admin`.