Software / code / prosody-modules
Changeset
6336:6e80b2cb5fe6
mod_http_oauth2: Show scope descriptions
This should help the user understand and provide _informed_ consent,
although the texts can certainly be improved. Explaining these scopes is
non-trivial.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Tue, 15 Jul 2025 16:28:40 +0200 |
| parents | 6335:9102d75131e4 |
| children | 6337:486115e3b64d |
| files | mod_http_oauth2/html/consent.html mod_http_oauth2/mod_http_oauth2.lua |
| diffstat | 2 files changed, 45 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/mod_http_oauth2/html/consent.html Tue Jul 15 12:21:23 2025 +0200 +++ b/mod_http_oauth2/html/consent.html Tue Jul 15 16:28:40 2025 +0200 @@ -35,8 +35,12 @@ <dd><a href="{client.policy_uri}">View policy</a></dd>} <dt>Requested permissions</dt> - <dd>{scopes# - <input class="scope" type="checkbox" id="scope_{idx}" name="scope" value="{item}" checked="" /><label class="scope" for="scope_{idx}">{item}</label>} + <dd> + <dl>{scopes# + <dt><input class="scope" type="checkbox" id="scope_{idx}" name="scope" value="{item.scope}" checked="" /> + <label class="scope" for="scope_{idx}">{item.title?{item.claim}}</label></dt> + {item.description&<dd>{item.description}</dd>}} + </ul> </dd> </dl>
--- a/mod_http_oauth2/mod_http_oauth2.lua Tue Jul 15 12:21:23 2025 +0200 +++ b/mod_http_oauth2/mod_http_oauth2.lua Tue Jul 15 16:28:40 2025 +0200 @@ -188,18 +188,22 @@ local openid_claims = set.new(); -module:add_item("openid-claim", "openid"); +module:add_item("openid-claim", { claim = "openid"; title = "OpenID"; + description = "Tells the application your JID and when you authenticated."; }); -- https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess -- The "offline_access" scope grants access to refresh tokens -module:add_item("openid-claim", "offline_access"); +module:add_item("openid-claim", { claim = "offline_access"; title = "Offline Access"; + description = "Application may renew access without interaction."; }); module:handle_items("openid-claim", function(event) authorization_server_metadata = nil; - openid_claims:add(event.item); + openid_claims:add(event.item.claim or event.item); end, function() authorization_server_metadata = nil; - openid_claims = set.new(module:get_host_items("openid-claim")); + openid_claims = set.new(array.new(module:get_host_items("openid-claim")):map(function(item) + return item.claim or item; + end)); end, true); -- array -> array, array, array @@ -1031,7 +1035,31 @@ else -- Render consent page - return render_page(templates.consent, { state = auth_state; client = client; scopes = scopes+roles }, true); + module:log("debug", "scopes=%q", scopes); + local scope_choices = array.new(module:get_host_items("openid-claim")):map(function(item) + if type(item) == "string" then + return { claim = item }; + elseif type(item) == "table" and type(item.claim) == "string" then + return item; + end + end):filter(function (item) + if array_contains(scopes, item.claim) then + module:log("debug", "scopes contains %q", item); + return true; + else + module:log("debug", "scopes contains NO %q", item); + return false; + end + end); + for _, role in ipairs(roles) do + if role == "xmpp" then + scope_choices:push({ scope = role; title = "XMPP"; + description = "Unlimited access to your account, including sending and receiving messages."; }); + else + scope_choices:push({ scope = role; title = role, description = "Prosody Role" }); + end + end + return render_page(templates.consent, { state = auth_state; client = client; scopes = scope_choices }, true); end elseif not auth_state.consent then -- Notify client of rejection @@ -1056,10 +1084,12 @@ local client_secret = make_client_secret(params.client_id); local id_token_signer = jwt.new_signer("HS256", client_secret); id_token = id_token_signer({ - iss = get_issuer(); - sub = url.build({ scheme = "xmpp"; path = user_jid }); - aud = params.client_id; - auth_time = auth_state.user.iat; + iss = get_issuer(); -- REQUIRED + sub = url.build({ scheme = "xmpp"; path = user_jid }); -- REQUIRED + aud = params.client_id; -- REQUIRED + -- exp REQUIRED, set by util.jwt + -- iat REQUIRED, set by util.jwt + auth_time = auth_state.user.iat; -- REQUIRED when Essential Claim, otherwise OPTIONAL nonce = params.nonce; amr = auth_state.user.amr; -- RFC 8176: Authentication Method Reference Values });