Class: KeycloakSdk::AuthClient
- Inherits:
-
Object
- Object
- KeycloakSdk::AuthClient
- Includes:
- TokenProvider
- Defined in:
- lib/keycloak_sdk/auth_client.rb
Overview
인증 파사드. rack-oauth2를 래핑(그랜트·PKCE)하고 introspection(RFC7662)·logout은 Faraday로 손수 수행한다. TokenProvider를 구현하지만(직접 사용용), admin은 캐싱 ClientCredentialsTokenProvider를 별도로 쓴다(§4).
Instance Method Summary collapse
-
#access_token ⇒ Object
TokenProvider 계약(직접 사용용).
- #client_credentials_token ⇒ Object
- #create_authorization_request(redirect_uri:, scopes: nil, state: SecureRandom.urlsafe_base64(24), nonce: nil) ⇒ Object
-
#exchange_code(code:, code_verifier:, redirect_uri:, expected_nonce: nil) ⇒ Object
expected_nonce가 주어지면(create_authorization_request가 돌려준 nonce) 응답 id_token을 realm JWKS로 서명·iss·aud·exp까지 강화 검증한 뒤 nonce 클레임을 대조한다 — OIDC nonce 재생 방지. -
#initialize(config:, http:, jwt_validator:) ⇒ AuthClient
constructor
A new instance of AuthClient.
- #introspect(token) ⇒ Object
- #logout(refresh_token:) ⇒ Object
- #refresh(refresh_token:) ⇒ Object
- #validate(token) ⇒ Object
Constructor Details
#initialize(config:, http:, jwt_validator:) ⇒ AuthClient
Returns a new instance of AuthClient.
14 15 16 17 18 19 20 |
# File 'lib/keycloak_sdk/auth_client.rb', line 14 def initialize(config:, http:, jwt_validator:) @config = config @http = http @jwt_validator = jwt_validator @endpoints = OidcEndpoints.from_config(config) configure_rack_oauth2_timeouts(config) end |
Instance Method Details
#access_token ⇒ Object
TokenProvider 계약(직접 사용용). admin은 캐싱 provider를 별도로 쓴다.
70 71 72 |
# File 'lib/keycloak_sdk/auth_client.rb', line 70 def access_token client_credentials_token.access_token end |
#client_credentials_token ⇒ Object
61 62 63 64 65 66 67 |
# File 'lib/keycloak_sdk/auth_client.rb', line 61 def client_credentials_token to_token_set(oauth_client.access_token!(scope: @config.scopes.join(" "))) rescue Rack::OAuth2::Client::Error => e raise AuthError.new("client-credentials failed: #{e.}", oauth_error: e.response[:error].to_s) rescue Faraday::Error => e raise TransportError, "token endpoint transport error: #{e.}" end |
#create_authorization_request(redirect_uri:, scopes: nil, state: SecureRandom.urlsafe_base64(24), nonce: nil) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/keycloak_sdk/auth_client.rb', line 22 def (redirect_uri:, scopes: nil, state: SecureRandom.urlsafe_base64(24), nonce: nil) verifier = SecureRandom.urlsafe_base64(64) challenge = Base64.urlsafe_encode64(Digest::SHA256.digest(verifier), padding: false) params = { scope: (scopes || @config.scopes).join(" "), state: state, code_challenge: challenge, code_challenge_method: :S256 } params[:nonce] = nonce if nonce url = oauth_client(redirect_uri: redirect_uri).(params) AuthorizationRequest.new(url: url.to_s, state: state, code_verifier: verifier) end |
#exchange_code(code:, code_verifier:, redirect_uri:, expected_nonce: nil) ⇒ Object
expected_nonce가 주어지면(create_authorization_request가 돌려준 nonce) 응답 id_token을
realm JWKS로 서명·iss·aud·exp까지 강화 검증한 뒤 nonce 클레임을 대조한다 — OIDC nonce 재생
방지. 불일치·부재·검증실패는 모두 거부(fail-closed). 생략 시 id_token 검증을 건너뛴다(무-nonce 흐름).
39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/keycloak_sdk/auth_client.rb', line 39 def exchange_code(code:, code_verifier:, redirect_uri:, expected_nonce: nil) client = oauth_client(redirect_uri: redirect_uri) client. = code token_set = to_token_set(client.access_token!(code_verifier: code_verifier)) verify_nonce!(token_set.id_token, expected_nonce) unless expected_nonce.nil? token_set rescue Rack::OAuth2::Client::Error => e raise AuthError.new("authorization_code exchange failed: #{e.}", oauth_error: e.response[:error].to_s) rescue Faraday::Error => e raise TransportError, "token endpoint transport error: #{e.}" end |
#introspect(token) ⇒ Object
74 75 76 77 78 79 80 81 82 83 |
# File 'lib/keycloak_sdk/auth_client.rb', line 74 def introspect(token) resp = @http.post(@endpoints.introspection, { token: token, client_id: @config.client_id, client_secret: @config.client_secret }) raise AuthError, "introspection failed: HTTP #{resp.status}" unless resp.success? IntrospectionResult.from_response(resp.body) rescue Faraday::Error => e raise TransportError, "introspection transport error: #{e.}" end |
#logout(refresh_token:) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/keycloak_sdk/auth_client.rb', line 85 def logout(refresh_token:) resp = @http.post(@endpoints.end_session, { client_id: @config.client_id, client_secret: @config.client_secret, refresh_token: refresh_token }) raise AuthError, "logout failed: HTTP #{resp.status}" unless resp.success? nil rescue Faraday::Error => e raise TransportError, "logout transport error: #{e.}" end |
#refresh(refresh_token:) ⇒ Object
51 52 53 54 55 56 57 58 59 |
# File 'lib/keycloak_sdk/auth_client.rb', line 51 def refresh(refresh_token:) client = oauth_client client.refresh_token = refresh_token to_token_set(client.access_token!) rescue Rack::OAuth2::Client::Error => e raise AuthError.new("refresh failed: #{e.}", oauth_error: e.response[:error].to_s) rescue Faraday::Error => e raise TransportError, "token endpoint transport error: #{e.}" end |
#validate(token) ⇒ Object
97 98 99 |
# File 'lib/keycloak_sdk/auth_client.rb', line 97 def validate(token) @jwt_validator.validate(token) end |