Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/cmd/create/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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")?;
}

Expand Down
14 changes: 13 additions & 1 deletion src/oidc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -103,6 +103,18 @@ pub fn extra_scopes(scope: Option<&str>) -> impl Iterator<Item = Scope> {
.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 <https://github.com/ctron/oidc-cli/pull/14> for context and
/// <https://dexidp.io/docs/configuration/custom-scopes-claims-clients/>.
pub fn other_audiences(scope: Option<&str>) -> impl Iterator<Item = Audience> {
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::<RefreshTokenClaims, Empty>::new_encoded(refresh_token).unverified_payload()
Expand Down