use tonic::{Request, Response, Status}; use crate::pb::core::token_service_server::TokenService as TokenServiceTrait; use crate::pb::core::{ GetSigningKeysRequest, GetSigningKeysResponse, IssueTokenRequest, IssueTokenResponse, RefreshTokenRequest, RefreshTokenResponse, RevokeTokenRequest, RevokeTokenResponse, SigningKey, TokenClaims as PbTokenClaims, VerifyTokenRequest, VerifyTokenResponse, revoke_token_request::Target, }; use crate::service::internal_auth::TokenService; pub struct TokenGrpcService { service: TokenService, } impl TokenGrpcService { pub fn new(service: TokenService) -> Self { Self { service } } } #[tonic::async_trait] impl TokenServiceTrait for TokenGrpcService { async fn issue_token( &self, request: Request, ) -> Result, Status> { let req = request.into_inner(); if req.user_id.is_empty() { return Err(Status::invalid_argument("user_id is required")); } let ttl = if req.ttl_secs > 0 { req.ttl_secs } else { 3600 }; let tokens = self .service .issue_token( &req.user_id, ttl, req.scopes, req.extra, ) .await .map_err(|e| Status::internal(e.to_string()))?; Ok(Response::new(IssueTokenResponse { access_token: tokens.access_token, refresh_token: tokens.refresh_token, expires_at: tokens.expires_at, key_id: tokens.key_id, })) } async fn refresh_token( &self, request: Request, ) -> Result, Status> { let req = request.into_inner(); let tokens = self .service .refresh_token(&req.refresh_token, 3600) .await .map_err(|e| Status::unauthenticated(e.to_string()))?; Ok(Response::new(RefreshTokenResponse { access_token: tokens.access_token, refresh_token: tokens.refresh_token, expires_at: tokens.expires_at, key_id: tokens.key_id, })) } async fn revoke_token( &self, request: Request, ) -> Result, Status> { let req = request.into_inner(); match req.target { Some(Target::Jti(jti)) => { self.service .revoke_by_jti(&jti, 86400) .await .map_err(|e| Status::internal(e.to_string()))?; Ok(Response::new(RevokeTokenResponse { revoked_count: 1 })) } Some(Target::UserId(user_id)) => { let count = self .service .revoke_user_tokens(&user_id) .await .map_err(|e| Status::internal(e.to_string()))?; Ok(Response::new(RevokeTokenResponse { revoked_count: count as i32, })) } None => Err(Status::invalid_argument("target is required")), } } async fn verify_token( &self, request: Request, ) -> Result, Status> { let req = request.into_inner(); match self .service .verify_token(&req.token) .await .map_err(|e| Status::internal(e.to_string()))? { Ok(claims) => Ok(Response::new(VerifyTokenResponse { valid: true, claims: Some(PbTokenClaims { sub: claims.sub, iss: claims.iss, iat: claims.iat, exp: claims.exp, jti: claims.jti, scope: claims.scope, extra: claims.extra, }), reason: String::new(), })), Err(reason) => Ok(Response::new(VerifyTokenResponse { valid: false, claims: None, reason, })), } } async fn get_signing_keys( &self, _request: Request, ) -> Result, Status> { let (keys, next_rotation_at) = self .service .get_signing_keys() .await .map_err(|e| Status::internal(e.to_string()))?; Ok(Response::new(GetSigningKeysResponse { keys: keys .into_iter() .map(|k| SigningKey { kid: k.kid, algorithm: k.algorithm, key_material: k.key_material, issued_at: k.issued_at, expires_at: k.expires_at, active: k.active, }) .collect(), next_rotation_at, })) } }