From 3bfe358991b37cdf52f495955eb755a91c1a2652 Mon Sep 17 00:00:00 2001 From: David Michael Barr Date: Tue, 2 Dec 2025 12:05:07 +0900 Subject: [PATCH] feat: accept audience from scope audience:server:client_id --- src/cmd/create/public.rs | 11 +++++++++-- src/oidc.rs | 14 +++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/cmd/create/public.rs b/src/cmd/create/public.rs index 8f2013d..29856d8 100644 --- a/src/cmd/create/public.rs +++ b/src/cmd/create/public.rs @@ -2,7 +2,7 @@ use crate::{ cmd::create::CreateCommon, config::{Client, ClientType, Config}, http::{HttpOptions, create_client}, - oidc::{extra_scopes, refresh_token_request}, + oidc::{extra_scopes, other_audiences, refresh_token_request}, server::{Bind, Server}, utils::OrNone, }; @@ -221,9 +221,16 @@ Open the following URL in your browser and perform the interactive login process // check ID token if let Some(id_token) = token.extra_fields().id_token() { + let scopes = self.common.scope.as_deref(); + let verifier = + client + .id_token_verifier() + .set_other_audience_verifier_fn(move |other| { + other_audiences(scopes).any(|aud| other == &aud) + }); id_token .clone() - .into_claims(&client.id_token_verifier(), &nonce) + .into_claims(&verifier, &nonce) .context("failed to verify ID token")?; } diff --git a/src/oidc.rs b/src/oidc.rs index 890a662..b52f711 100644 --- a/src/oidc.rs +++ b/src/oidc.rs @@ -8,7 +8,7 @@ use anyhow::{anyhow, bail}; use biscuit::{Empty, jws::Compact}; use oauth2::{EndpointMaybeSet, EndpointNotSet, EndpointSet, RefreshToken}; use openidconnect::{ - ClientId, ClientSecret, IssuerUrl, Scope, + Audience, ClientId, ClientSecret, IssuerUrl, Scope, core::{CoreClient, CoreProviderMetadata, CoreTokenResponse}, }; use time::OffsetDateTime; @@ -103,6 +103,18 @@ pub fn extra_scopes(scope: Option<&str>) -> impl Iterator { .map(|s| Scope::new(s.into())) } +/// Other audiences specified in scope may be implicitly trusted. +/// The `audience:server:client_id:{CLIENT_ID}` format originates with GoogleAuthUtil. +/// See for context and +/// . +pub fn other_audiences(scope: Option<&str>) -> impl Iterator { + scope + .into_iter() + .flat_map(|s| s.split(' ')) + .filter_map(|s| s.strip_prefix("audience:server:client_id:")) + .map(|aud| Audience::new(aud.into())) +} + pub fn check_refresh_token_expiration(refresh_token: &str) -> anyhow::Result<()> { if let Ok(token) = Compact::::new_encoded(refresh_token).unverified_payload()