@@ -176,22 +176,6 @@ impl GatewayCredentials {
176176 self . inner . sandbox_bearer . clone ( )
177177 }
178178
179- /// The gateway session JWT these credentials currently present, as last
180- /// renewed, or `None` once revoked. The value is unverified; callers that
181- /// act on its claims must verify it first.
182- #[ cfg( feature = "jwt" ) ]
183- #[ must_use]
184- pub fn current_gateway_token ( & self ) -> Option < crate :: jwt:: SecretJwt > {
185- let bearer = self
186- . inner
187- . bearer
188- . read ( )
189- . unwrap_or_else ( std:: sync:: PoisonError :: into_inner)
190- . clone ( ) ?;
191- let token = crate :: auth:: strip_bearer_scheme ( bearer. to_str ( ) . ok ( ) ?) ?;
192- crate :: jwt:: SecretJwt :: parse ( token) . ok ( )
193- }
194-
195179 /// Clear both credentials and stop renewal. Existing clients fail their
196180 /// next request locally instead of presenting a revoked identity.
197181 pub fn revoke ( & self ) {
@@ -1577,50 +1561,43 @@ pub async fn exchange_provider_subject_token(
15771561 ) )
15781562}
15791563
1580- /// Confirm that the gateway still accepts this session's current credentials.
1581- ///
1582- /// The gateway authenticates every sandbox RPC against the persisted runtime
1583- /// generation, credential epoch, gateway-token lineage, and an active sandbox
1584- /// phase, so a successful authenticated read proves the session is current
1585- /// right now, not only when its JWT was signed. The response is discarded.
1586- #[ tracing:: instrument(
1587- name = "supervisor.gateway.confirm_session_authorization" ,
1588- skip_all,
1589- fields( otel. kind = "client" , otel. status_code = tracing:: field:: Empty )
1590- ) ]
1591- pub async fn confirm_session_authorization (
1564+ /// Obtain only the final access token; the gateway selects and verifies the
1565+ /// sandbox identity and resolves all grant parameters from its configuration.
1566+ #[ tracing:: instrument( name = "supervisor.gateway.get_provider_access_token" , skip_all) ]
1567+ pub async fn get_sandbox_provider_access_token (
15921568 gateway : & GatewayEndpoint ,
1593- sandbox_name : & str ,
1594- ) -> std :: result :: Result < ( ) , TokenGrantFailure > {
1595- let status = ClientSpanStatus :: current ( ) ;
1569+ credential_key : & str ,
1570+ request_id : Option < & str > ,
1571+ ) -> std :: result :: Result < ProviderSubjectTokenExchangeResult , TokenGrantFailure > {
15961572 let endpoint = token_grant_gateway_endpoint ( gateway. url ( ) ) ?;
1597- if sandbox_name. is_empty ( ) {
1598- return Err ( gateway_grant_failure ( TokenGrantFailureKind :: Configuration ) ) ;
1599- }
16001573 let mut client = connect ( & gateway. with_url ( endpoint. as_str ( ) ) )
16011574 . await
16021575 . map_err ( |_| gateway_grant_failure ( TokenGrantFailureKind :: Unavailable ) ) ?;
1603- let result = client
1604- . get_sandbox_config ( GetSandboxConfigRequest {
1605- workspace_scope : None ,
1606- name : sandbox_name. to_string ( ) ,
1607- } )
1608- . await
1609- . map ( drop)
1610- . map_err ( |status| {
1611- gateway_grant_failure ( match status. code ( ) {
1612- tonic:: Code :: Unauthenticated
1613- | tonic:: Code :: PermissionDenied
1614- | tonic:: Code :: NotFound
1615- | tonic:: Code :: FailedPrecondition => {
1616- TokenGrantFailureKind :: WorkloadIdentityRejected
1617- }
1618- tonic:: Code :: DeadlineExceeded => TokenGrantFailureKind :: Timeout ,
1619- tonic:: Code :: Unavailable => TokenGrantFailureKind :: Unavailable ,
1620- _ => TokenGrantFailureKind :: Unclassified ,
1621- } )
1622- } ) ;
1623- status. finish ( result)
1576+ let mut request = tonic:: Request :: new ( crate :: proto:: GetSandboxProviderAccessTokenRequest {
1577+ credential_key : credential_key. to_string ( ) ,
1578+ } ) ;
1579+ if let Some ( value) = request_id. and_then ( |value| value. parse ( ) . ok ( ) ) {
1580+ request. metadata_mut ( ) . insert ( "x-request-id" , value) ;
1581+ }
1582+ let response = tokio:: time:: timeout (
1583+ Duration :: from_mins ( 1 ) ,
1584+ client. get_sandbox_provider_access_token ( request) ,
1585+ )
1586+ . await
1587+ . map_err ( |_| gateway_grant_failure ( TokenGrantFailureKind :: Timeout ) ) ?
1588+ . map_err ( |status| provider_subject_token_exchange_status ( & status, & endpoint) ) ?
1589+ . into_inner ( ) ;
1590+ // connect() and the response boundary both reject a locally revoked session.
1591+ if gateway. credentials ( ) . is_revoked ( ) {
1592+ return Err ( gateway_grant_failure (
1593+ TokenGrantFailureKind :: WorkloadIdentityRejected ,
1594+ ) ) ;
1595+ }
1596+ provider_subject_token_exchange_result ( crate :: proto:: ExchangeProviderSubjectTokenResponse {
1597+ access_token : response. access_token ,
1598+ expires_after : response. expires_after ,
1599+ token_type : response. token_type ,
1600+ } )
16241601}
16251602
16261603/// Attach the exchange's request ID as `x-request-id` gRPC metadata.
0 commit comments