Include the hash of the access token in the JWT / ID Token under the key at_hash as per the requirements. Update the discovery endpoint to describe subject_type as 'pairwise', rather than 'public', since we do pairwise subject ids.
This commit is contained in:
@@ -26,7 +26,7 @@ class OidcController < ApplicationController
|
||||
response_types_supported: ["code"],
|
||||
response_modes_supported: ["query"],
|
||||
grant_types_supported: ["authorization_code", "refresh_token"],
|
||||
subject_types_supported: ["public"],
|
||||
subject_types_supported: ["pairwise"],
|
||||
id_token_signing_alg_values_supported: ["RS256"],
|
||||
scopes_supported: ["openid", "profile", "email", "groups", "offline_access"],
|
||||
token_endpoint_auth_methods_supported: ["client_secret_post", "client_secret_basic"],
|
||||
@@ -422,8 +422,14 @@ class OidcController < ApplicationController
|
||||
return
|
||||
end
|
||||
|
||||
# Generate ID token (JWT) with pairwise SID
|
||||
id_token = OidcJwtService.generate_id_token(user, application, consent: consent, nonce: auth_code.nonce)
|
||||
# Generate ID token (JWT) with pairwise SID and at_hash
|
||||
id_token = OidcJwtService.generate_id_token(
|
||||
user,
|
||||
application,
|
||||
consent: consent,
|
||||
nonce: auth_code.nonce,
|
||||
access_token: access_token_record.plaintext_token
|
||||
)
|
||||
|
||||
# Return tokens
|
||||
render json: {
|
||||
@@ -539,8 +545,13 @@ class OidcController < ApplicationController
|
||||
return
|
||||
end
|
||||
|
||||
# Generate new ID token (JWT with pairwise SID, no nonce for refresh grants)
|
||||
id_token = OidcJwtService.generate_id_token(user, application, consent: consent)
|
||||
# Generate new ID token (JWT with pairwise SID and at_hash, no nonce for refresh grants)
|
||||
id_token = OidcJwtService.generate_id_token(
|
||||
user,
|
||||
application,
|
||||
consent: consent,
|
||||
access_token: new_access_token.plaintext_token
|
||||
)
|
||||
|
||||
# Return new tokens
|
||||
render json: {
|
||||
|
||||
@@ -3,7 +3,7 @@ class OidcJwtService
|
||||
|
||||
class << self
|
||||
# Generate an ID token (JWT) for the user
|
||||
def generate_id_token(user, application, consent: nil, nonce: nil)
|
||||
def generate_id_token(user, application, consent: nil, nonce: nil, access_token: nil)
|
||||
now = Time.current.to_i
|
||||
# Use application's configured ID token TTL (defaults to 1 hour)
|
||||
ttl = application.id_token_expiry_seconds
|
||||
@@ -26,6 +26,14 @@ class OidcJwtService
|
||||
# Add nonce if provided (OIDC requires this for implicit flow)
|
||||
payload[:nonce] = nonce if nonce.present?
|
||||
|
||||
# Add at_hash if access token is provided (OIDC Core spec §3.1.3.6)
|
||||
# at_hash = left-most 128 bits of SHA-256 hash of access token, base64url encoded
|
||||
if access_token.present?
|
||||
sha256 = Digest::SHA256.digest(access_token)
|
||||
at_hash = Base64.urlsafe_encode64(sha256[0..15], padding: false)
|
||||
payload[:at_hash] = at_hash
|
||||
end
|
||||
|
||||
# Add groups if user has any
|
||||
if user.groups.any?
|
||||
payload[:groups] = user.groups.pluck(:name)
|
||||
|
||||
Reference in New Issue
Block a user