pub struct JwtService { /* private fields */ }Expand description
Signs and validates JWTs. Provide this into the DI container so the framework
boundaries (boundary.rs, ws.rs) can auto-populate RequestContext::claims()
on every incoming request.
§Secret rotation
Keys live behind Rotating (an
ArcSwap): the request path pays one atomic pointer load, while
rotate_secret — typically driven by a
SecretSource watcher — swaps in a new bundle with no restart. The
previous key is retained for verification, so live tokens (≤ TTL old)
keep validating through the grace window.
Token signing returns Result<_, JwtSignError> — a malformed key from
a bad rotation payload must surface as a 500 on the affected request,
never as a process panic.
Implementations§
Source§impl JwtService
impl JwtService
pub fn new(config: JwtConfig) -> Self
Sourcepub fn rotate_secret(&self, new_secret: &[u8], version: u64)
pub fn rotate_secret(&self, new_secret: &[u8], version: u64)
Hot-swap the signing secret — no restart, no token mass-invalidation.
New tokens sign with the new key immediately; tokens signed with the previous key keep verifying until natural expiry. Versions are monotonic: a stale (≤ current) version is ignored, making concurrent watchers and duplicate delivery harmless.
Sourcepub fn issue_access(
&self,
sub: &str,
role: &str,
email: &str,
) -> Result<String, JwtSignError>
pub fn issue_access( &self, sub: &str, role: &str, email: &str, ) -> Result<String, JwtSignError>
Issue a signed access token.
Claims: sub = user ID, role, email, type = "access", jti, iat, exp.
Signing can only fail on malformed key material (e.g. a bad rotation payload) — propagate the error instead of panicking mid-traffic.
Sourcepub fn issue_access_with_perms(
&self,
sub: &str,
role: &str,
email: &str,
perms: &[String],
) -> Result<String, JwtSignError>
pub fn issue_access_with_perms( &self, sub: &str, role: &str, email: &str, perms: &[String], ) -> Result<String, JwtSignError>
Like Self::issue_access but embeds a perms claim (array of permission strings).
Use this when the app maintains a permission map so that PermissionGuard
can do a zero-latency lookup without hitting the store on each request.
Sourcepub fn issue_access_bound(
&self,
sub: &str,
role: &str,
email: &str,
perms: &[String],
tenant: Option<&str>,
) -> Result<String, JwtSignError>
pub fn issue_access_bound( &self, sub: &str, role: &str, email: &str, perms: &[String], tenant: Option<&str>, ) -> Result<String, JwtSignError>
Like Self::issue_access_with_perms but additionally binds the token to
a tenant via the tenant claim. TenantGuard then enforces that
requests carrying this token resolve to the same tenant — omitting or
forging the tenant header yields 403, so a suspended tenant’s users
cannot ride the fallback pool by dropping the header.
Sourcepub fn issue_refresh(&self, sub: &str) -> Result<(String, String), JwtSignError>
pub fn issue_refresh(&self, sub: &str) -> Result<(String, String), JwtSignError>
Issue a signed refresh token with a unique jti.
Claims: sub, type = "refresh", jti, iat, exp.
The jti is returned alongside the token so the caller can persist it.
Sourcepub fn decode(&self, token: &str) -> Option<Arc<Claims>>
pub fn decode(&self, token: &str) -> Option<Arc<Claims>>
Validate signature + expiry and return the decoded claims as a JSON map.
Returns None for any invalid token (expired, bad signature, malformed).
Does NOT enforce token type — use Self::decode_access at request boundaries.
Sourcepub fn decode_access(&self, token: &str) -> Option<Arc<Claims>>
pub fn decode_access(&self, token: &str) -> Option<Arc<Claims>>
Like decode but additionally requires "type" == "access".
Use this at request boundaries so refresh tokens cannot be passed as access tokens to authenticate protected routes.
Sourcepub fn validate_refresh(&self, token: &str) -> Option<(String, String)>
pub fn validate_refresh(&self, token: &str) -> Option<(String, String)>
Validate a refresh token specifically.
Returns (subject, jti) on success, None otherwise.
Callers must verify that the jti exists in their token store before
issuing a new pair.
Sourcepub fn access_ttl_secs(&self) -> u64
pub fn access_ttl_secs(&self) -> u64
Lifetime of access tokens in seconds (used in TokenResponse.expires_in).
Sourcepub fn refresh_ttl_secs(&self) -> u64
pub fn refresh_ttl_secs(&self) -> u64
Lifetime of refresh tokens (used by token store for TTL).
Auto Trait Implementations§
impl !Freeze for JwtService
impl RefUnwindSafe for JwtService
impl Send for JwtService
impl Sync for JwtService
impl Unpin for JwtService
impl UnsafeUnpin for JwtService
impl UnwindSafe for JwtService
Blanket Implementations§
Source§impl<T> AggregateExpressionMethods for T
impl<T> AggregateExpressionMethods for T
Source§fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
DISTINCT modifier for aggregate functions Read moreSource§fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
ALL modifier for aggregate functions Read moreSource§fn aggregate_filter<P>(self, f: P) -> Self::Output
fn aggregate_filter<P>(self, f: P) -> Self::Output
Source§fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::RequestSource§impl<T> IntoSql for T
impl<T> IntoSql for T
Source§fn into_sql<T>(self) -> Self::Expression
fn into_sql<T>(self) -> Self::Expression
self to an expression for Diesel’s query builder. Read moreSource§fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
&self to an expression for Diesel’s query builder. Read more