diff --git a/crates/handlers/src/oauth2/discovery.rs b/crates/handlers/src/oauth2/discovery.rs index 132afc0d..838b2cc1 100644 --- a/crates/handlers/src/oauth2/discovery.rs +++ b/crates/handlers/src/oauth2/discovery.rs @@ -27,6 +27,7 @@ use mas_warp_utils::filters::{self, url_builder::UrlBuilder}; use oauth2_types::{ oidc::{ClaimType, Metadata, SubjectType}, requests::{Display, GrantType, ResponseMode}, + scope, }; use warp::{filters::BoxedFilter, Filter, Reply}; @@ -72,7 +73,8 @@ pub(super) fn filter( let scopes_supported = Some({ let mut s = HashSet::new(); - s.insert("openid".to_string()); + s.insert(scope::OPENID.to_string()); + s.insert(scope::EMAIL.to_string()); s }); diff --git a/crates/handlers/src/oauth2/token.rs b/crates/handlers/src/oauth2/token.rs index 391dccb6..23fe5ef1 100644 --- a/crates/handlers/src/oauth2/token.rs +++ b/crates/handlers/src/oauth2/token.rs @@ -22,10 +22,7 @@ use hyper::StatusCode; use mas_config::{ClientConfig, ClientsConfig, HttpConfig}; use mas_data_model::{AuthorizationGrantStage, TokenType}; use mas_iana::{jose::JsonWebSignatureAlg, oauth::OAuthClientAuthenticationMethod}; -use mas_jose::{ - claims::{AT_HASH, AUD, AUTH_TIME, C_HASH, EXP, IAT, ISS, NONCE, SUB}, - DecodedJsonWebToken, SigningKeystore, StaticKeystore, -}; +use mas_jose::{claims, DecodedJsonWebToken, SigningKeystore, StaticKeystore}; use mas_storage::{ oauth2::{ access_token::{add_access_token, revoke_access_token}, @@ -50,7 +47,7 @@ use oauth2_types::{ requests::{ AccessTokenRequest, AccessTokenResponse, AuthorizationCodeGrant, RefreshTokenGrant, }, - scope::OPENID, + scope, }; use rand::thread_rng; use serde::Serialize; @@ -284,34 +281,41 @@ async fn authorization_code_grant( .await .wrap_error()?; - let id_token = if session.scope.contains(&OPENID) { + let id_token = if session.scope.contains(&scope::OPENID) { let mut claims = HashMap::new(); let now = Utc::now(); - ISS.insert(&mut claims, issuer.to_string()).wrap_error()?; - SUB.insert(&mut claims, &browser_session.user.sub) + claims::ISS + .insert(&mut claims, issuer.to_string()) .wrap_error()?; - AUD.insert(&mut claims, client.client_id.clone()) + claims::SUB + .insert(&mut claims, &browser_session.user.sub) .wrap_error()?; - IAT.insert(&mut claims, now).wrap_error()?; - EXP.insert(&mut claims, now + Duration::hours(1)) + claims::AUD + .insert(&mut claims, client.client_id.clone()) + .wrap_error()?; + claims::IAT.insert(&mut claims, now).wrap_error()?; + claims::EXP + .insert(&mut claims, now + Duration::hours(1)) .wrap_error()?; if let Some(ref nonce) = authz_grant.nonce { - NONCE.insert(&mut claims, nonce.clone()).wrap_error()?; + claims::NONCE + .insert(&mut claims, nonce.clone()) + .wrap_error()?; } if let Some(ref last_authentication) = browser_session.last_authentication { - AUTH_TIME + claims::AUTH_TIME .insert(&mut claims, last_authentication.created_at) .wrap_error()?; } - AT_HASH + claims::AT_HASH .insert( &mut claims, hash(Sha256::new(), &access_token_str).wrap_error()?, ) .wrap_error()?; - C_HASH + claims::C_HASH .insert(&mut claims, hash(Sha256::new(), &grant.code).wrap_error()?) .wrap_error()?; diff --git a/crates/handlers/src/oauth2/userinfo.rs b/crates/handlers/src/oauth2/userinfo.rs index 0e7170ca..e7140d73 100644 --- a/crates/handlers/src/oauth2/userinfo.rs +++ b/crates/handlers/src/oauth2/userinfo.rs @@ -18,14 +18,19 @@ use mas_warp_utils::filters::{ self, authenticate::{authentication, recover_unauthorized}, }; +use oauth2_types::scope; use serde::Serialize; +use serde_with::skip_serializing_none; use sqlx::PgPool; use warp::{filters::BoxedFilter, Filter, Rejection, Reply}; #[derive(Serialize)] +#[skip_serializing_none] struct UserInfo { sub: String, username: String, + email: Option, + email_verified: Option, } pub(super) fn filter(pool: &PgPool) -> BoxedFilter<(Box,)> { @@ -48,8 +53,19 @@ async fn userinfo( session: Session, ) -> Result, Rejection> { let user = session.browser_session.user; - Ok(Box::new(warp::reply::json(&UserInfo { + let mut res = UserInfo { sub: user.sub, username: user.username, - }))) + email: None, + email_verified: None, + }; + + if session.scope.contains(&scope::EMAIL) { + if let Some(email) = user.primary_email { + res.email_verified = Some(email.confirmed_at.is_some()); + res.email = Some(email.email); + } + } + + Ok(Box::new(warp::reply::json(&res))) }