pub struct JwtPlugin { /* private fields */ }Expand description
A minimal JWT implementation using HMAC-SHA256 (HS256).
For production, consider a full JWT library. This implementation uses real
cryptographic primitives (HMAC-SHA256 via the hmac and sha2 crates).
Implementations§
Source§impl JwtPlugin
impl JwtPlugin
pub fn new(secret: &str, expiry_secs: u64) -> Self
Sourcepub fn issue_with_kind(
&self,
user_id: &str,
kind: &str,
expiry_secs: u64,
) -> String
pub fn issue_with_kind( &self, user_id: &str, kind: &str, expiry_secs: u64, ) -> String
Issue a JWT with an explicit kind and expiry.
Sourcepub fn issue_pair(&self, user_id: &str, refresh_expiry_secs: u64) -> TokenPair
pub fn issue_pair(&self, user_id: &str, refresh_expiry_secs: u64) -> TokenPair
Issue a token pair: a short-lived access token and a long-lived refresh
token. The access token uses the plugin’s configured expiry; the refresh
token uses the provided refresh_expiry_secs.
Sourcepub fn refresh(&self, refresh_token: &str) -> Result<TokenPair, String>
pub fn refresh(&self, refresh_token: &str) -> Result<TokenPair, String>
Consume a refresh token and issue a new token pair.
Order of operations matters for security:
- Cryptographically verify the token FIRST. If we inserted into the replay cache before verification, an attacker could pollute the cache by posting random garbage, growing it unbounded. Worse, a real token presented alongside that garbage would get “burned” before we knew whether it was even valid.
- Then check the replay cache and atomically insert.
The window between verify() and insert() is a TOCTOU where two
concurrent refreshes of the same token could both succeed. The Mutex
around used_refresh_tokens is the serialization point — the check +
insert happens under the same lock.
Sourcepub fn verify(&self, token: &str) -> Result<Claims, String>
pub fn verify(&self, token: &str) -> Result<Claims, String>
Verify and decode a JWT. Returns claims if valid and not expired. Uses constant-time comparison for the signature to prevent timing attacks.
Sourcepub fn resolve_user(&self, token: &str) -> Option<String>
pub fn resolve_user(&self, token: &str) -> Option<String>
Resolve a JWT to a user ID. Returns None if invalid.
Trait Implementations§
Source§impl Plugin for JwtPlugin
impl Plugin for JwtPlugin
Source§fn on_init(&self, _ctx: &PluginContext)
fn on_init(&self, _ctx: &PluginContext)
Source§fn routes(&self) -> Vec<PluginRoute>
fn routes(&self) -> Vec<PluginRoute>
Source§fn before_insert(
&self,
_entity: &str,
_data: &mut Value,
_auth: &AuthContext,
) -> Result<(), PluginError>
fn before_insert( &self, _entity: &str, _data: &mut Value, _auth: &AuthContext, ) -> Result<(), PluginError>
Source§fn after_insert(
&self,
_entity: &str,
_id: &str,
_data: &Value,
_auth: &AuthContext,
)
fn after_insert( &self, _entity: &str, _id: &str, _data: &Value, _auth: &AuthContext, )
Source§fn before_update(
&self,
_entity: &str,
_id: &str,
_data: &mut Value,
_auth: &AuthContext,
) -> Result<(), PluginError>
fn before_update( &self, _entity: &str, _id: &str, _data: &mut Value, _auth: &AuthContext, ) -> Result<(), PluginError>
Source§fn after_update(
&self,
_entity: &str,
_id: &str,
_data: &Value,
_auth: &AuthContext,
)
fn after_update( &self, _entity: &str, _id: &str, _data: &Value, _auth: &AuthContext, )
Source§fn before_delete(
&self,
_entity: &str,
_id: &str,
_auth: &AuthContext,
) -> Result<(), PluginError>
fn before_delete( &self, _entity: &str, _id: &str, _auth: &AuthContext, ) -> Result<(), PluginError>
Source§fn after_delete(&self, _entity: &str, _id: &str, _auth: &AuthContext)
fn after_delete(&self, _entity: &str, _id: &str, _auth: &AuthContext)
Source§fn on_request(
&self,
_method: &str,
_path: &str,
_auth: &AuthContext,
) -> Result<(), PluginError>
fn on_request( &self, _method: &str, _path: &str, _auth: &AuthContext, ) -> Result<(), PluginError>
Source§fn on_request_with_meta(
&self,
method: &str,
path: &str,
auth: &AuthContext,
_meta: &RequestMeta<'_>,
) -> Result<(), PluginError>
fn on_request_with_meta( &self, method: &str, path: &str, auth: &AuthContext, _meta: &RequestMeta<'_>, ) -> Result<(), PluginError>
on_request] that also receives per-request
metadata (peer IP today; more fields may be added later). The
default implementation delegates to on_request so existing
plugins keep working without changes. Plugins that care about
IP — notably rate limiting — override this hook.