lib/rodauth/features/oidc.rb in rodauth-oauth-1.0.0.pre.beta2 vs lib/rodauth/features/oidc.rb in rodauth-oauth-1.0.0

- old
+ new

@@ -290,10 +290,15 @@ request.params["scope"] = sc.join(" ") end super + + return unless (response_type = param_or_nil("response_type")) + return unless response_type.include?("id_token") + + redirect_response_error("invalid_request") unless param_or_nil("nonce") end def require_authorizable_account try_prompt super @@ -438,14 +443,11 @@ else oauth_grant = valid_oauth_grant_ds.where(oauth_grants_code_column => authorization_code).first _generate_access_token(oauth_grant) end - { - "code" => authorization_code, - **json_access_token_payload(oauth_grants_token_column => access_token) - } + json_access_token_payload(oauth_grants_token_column => access_token).merge("code" => authorization_code) end def create_token(*) oauth_grant = super generate_id_token(oauth_grant) @@ -455,19 +457,32 @@ def generate_id_token(oauth_grant, include_claims = false) oauth_scopes = oauth_grant[oauth_grants_scopes_column].split(oauth_scope_separator) return unless oauth_scopes.include?("openid") + signing_algorithm = oauth_application[oauth_applications_id_token_signed_response_alg_column] || + oauth_jwt_keys.keys.first + id_token_claims = jwt_claims(oauth_grant) id_token_claims[:nonce] = oauth_grant[oauth_grants_nonce_column] if oauth_grant[oauth_grants_nonce_column] id_token_claims[:acr] = oauth_grant[oauth_grants_acr_column] if oauth_grant[oauth_grants_acr_column] # Time when the End-User authentication occurred. id_token_claims[:auth_time] = get_oidc_account_last_login_at(oauth_grant[oauth_grants_account_id_column]).to_i + # Access Token hash value. + if (access_token = oauth_grant[oauth_grants_token_column]) + id_token_claims[:at_hash] = id_token_hash(access_token, signing_algorithm) + end + + # code hash value. + if (code = oauth_grant[oauth_grants_code_column]) + id_token_claims[:c_hash] = id_token_hash(code, signing_algorithm) + end + account = db[accounts_table].where(account_id_column => oauth_grant[oauth_grants_account_id_column]).first # this should never happen! # a newly minted oauth token from a grant should have been assigned to an account # who just authorized its generation. @@ -486,14 +501,11 @@ # the resulting Claims are returned in the ID Token. fill_with_account_claims(id_token_claims, account, oauth_scopes, param_or_nil("claims_locales")) if include_claims params = { jwks: oauth_application_jwks(oauth_application), - signing_algorithm: ( - oauth_application[oauth_applications_id_token_signed_response_alg_column] || - oauth_jwt_keys.keys.first - ), + signing_algorithm: signing_algorithm, encryption_algorithm: oauth_application[oauth_applications_id_token_encrypted_response_alg_column], encryption_method: oauth_application[oauth_applications_id_token_encrypted_response_enc_column] }.compact oauth_grant[:id_token] = jwt_encode(id_token_claims, **params) @@ -653,19 +665,21 @@ "code" => params["code"] ) when "id_token token" redirect_response_error("invalid_request") unless supports_token_response_type? - oauth_grant = _do_authorize_token(oauth_grants_type_column => "hybrid") + grant_params = oidc_grant_params.merge(oauth_grants_type_column => "hybrid") + oauth_grant = _do_authorize_token(grant_params) generate_id_token(oauth_grant) response_params.replace(json_access_token_payload(oauth_grant)) when "code id_token token" redirect_response_error("invalid_request") unless supports_token_response_type? params = create_oauth_grant_with_token oauth_grant = valid_oauth_grant_ds.where(oauth_grants_code_column => params["code"]).first + oauth_grant[oauth_grants_token_column] = params["access_token"] generate_id_token(oauth_grant) response_params.replace(params.merge("id_token" => oauth_grant[:id_token])) when "none" response_mode ||= "none" @@ -782,8 +796,22 @@ else response["Cache-Control"] = "no-store" response["Pragma"] = "no-cache" end return_response(jwt) + end + + def id_token_hash(hash, algo) + digest = case algo + when /256/ then Digest::SHA256 + when /384/ then Digest::SHA384 + when /512/ then Digest::SHA512 + end + + return unless digest + + hash = digest.digest(hash) + hash = hash[0...hash.size / 2] + Base64.urlsafe_encode64(hash).tr("=", "") end end end