MCPcopy Create free account
hub / github.com/NVIDIA/OpenShell / validate_token

Method validate_token

crates/openshell-server/src/auth/oidc.rs:288–349  ·  view source on GitHub ↗

Validate a JWT and return an `Identity`. This is the authentication step — it verifies the caller's identity but does not check authorization (that's `authz::AuthzPolicy::check`).

(&self, token: &str)

Source from the content-addressed store, hash-verified

286 /// This is the authentication step — it verifies the caller's identity
287 /// but does not check authorization (that's `authz::AuthzPolicy::check`).
288 pub async fn validate_token(&self, token: &str) -> Result<Identity, Status> {
289 self.refresh_if_stale().await.map_err(|e| {
290 warn!(error = %e, "JWKS refresh failed");
291 Status::internal("OIDC key refresh failed")
292 })?;
293
294 // Decode the header to find the key ID.
295 let header = decode_header(token).map_err(|e| {
296 debug!(error = %e, "Failed to decode JWT header");
297 Status::unauthenticated("invalid token")
298 })?;
299
300 let kid = header.kid.ok_or_else(|| {
301 debug!("JWT has no kid in header");
302 Status::unauthenticated("invalid token: missing kid")
303 })?;
304
305 // Look up the key in cache.
306 let keys = self.keys.read().await;
307 let decoding_key = if let Some(k) = keys.get(&kid) {
308 k.clone()
309 } else {
310 // Key not found -- try refreshing once (key rotation).
311 drop(keys);
312 self.refresh_keys_coalesced().await.map_err(|e| {
313 warn!(error = %e, "JWKS refresh on kid miss failed");
314 Status::internal("OIDC key refresh failed")
315 })?;
316 let keys = self.keys.read().await;
317 keys.get(&kid).cloned().ok_or_else(|| {
318 debug!(kid = %kid, "JWT kid not found in JWKS");
319 Status::unauthenticated("invalid token: unknown signing key")
320 })?
321 };
322
323 // Validate the JWT.
324 let mut validation = Validation::new(Algorithm::RS256);
325 validation.set_issuer(&[&self.config.issuer]);
326 validation.set_audience(&[&self.config.audience]);
327
328 let token_data = decode::<OidcClaims>(token, &decoding_key, &validation).map_err(|e| {
329 debug!(error = %e, "JWT validation failed");
330 Status::unauthenticated(format!("invalid token: {e}"))
331 })?;
332
333 let mut claims = token_data.claims;
334 claims.extract_roles(&self.config.roles_claim);
335
336 let scopes = if self.config.scopes_claim.is_empty() {
337 vec![]
338 } else {
339 claims.extract_scopes(&self.config.scopes_claim)
340 };
341
342 Ok(Identity {
343 subject: claims.sub,
344 display_name: claims.preferred_username,
345 roles: claims.roles,

Callers 1

authenticateMethod · 0.80

Calls 7

refresh_if_staleMethod · 0.80
extract_rolesMethod · 0.80
extract_scopesMethod · 0.80
readMethod · 0.45
getMethod · 0.45
is_emptyMethod · 0.45

Tested by

no test coverage detected