module Okta::Jwt
Constants
- JWKS_CACHE
keys are cached under their kid value
- VERSION
Attributes
auth_server_id[RW]
issuer[RW]
logger[RW]
Public Instance Methods
client(issuer)
click to toggle source
init client
# File lib/okta/jwt.rb, line 92 def client(issuer) Faraday.new(url: issuer) do |f| f.use Faraday::Adapter::NetHttp f.headers['Accept'] = 'application/json' end end
configure!(issuer:, logger: nil)
click to toggle source
configure the client for signing in
# File lib/okta/jwt.rb, line 21 def configure!(issuer:, logger: nil) @issuer = issuer @auth_server_id = issuer.split('/').last end
get_jwk(header, payload)
click to toggle source
extract public key from metadata's jwks_uri using kid
# File lib/okta/jwt.rb, line 62 def get_jwk(header, payload) kid = header['kid'] # cache hit return JWKS_CACHE[kid] if JWKS_CACHE[kid] # fetch jwk logger.info("[Okta::Jwt] Fetching public key: kid => #{kid} ...") if logger jwks_response = client(payload['iss']).get do |req| req.url get_metadata(payload)['jwks_uri'] end jwk = JSON.parse(jwks_response.body)['keys'].find do |key| key.dig('kid') == kid end # cache and return the key jwk.tap{JWKS_CACHE[kid] = jwk} end
get_metadata(payload)
click to toggle source
fetch client metadata using cid/aud
# File lib/okta/jwt.rb, line 82 def get_metadata(payload) auth_server_id = payload['iss'].split('/').last # iss: "https://<org>.oktapreview.com/oauth2/<auth_server_id>" client_id = payload['cid'] metadata_response = client(payload['iss']).get do |req| req.url "/oauth2/#{auth_server_id}/.well-known/oauth-authorization-server?client_id=#{client_id}" end JSON.parse(metadata_response.body) end
sign_in_client(client_id:, client_secret:, scope:)
click to toggle source
sign in client to get access_token
# File lib/okta/jwt.rb, line 37 def sign_in_client(client_id:, client_secret:, scope:) client(issuer).post do |req| req.url "/oauth2/#{auth_server_id}/v1/token" req.headers['Content-Type'] = 'application/x-www-form-urlencoded' req.headers['Authorization'] = 'Basic: ' + Base64.strict_encode64("#{client_id}:#{client_secret}") req.body = URI.encode_www_form scope: scope, grant_type: 'client_credentials' end end
sign_in_user(username:, password:, client_id:, client_secret:, scope: 'openid')
click to toggle source
sign in user to get tokens
# File lib/okta/jwt.rb, line 27 def sign_in_user(username:, password:, client_id:, client_secret:, scope: 'openid') client(issuer).post do |req| req.url "/oauth2/#{auth_server_id}/v1/token" req.headers['Content-Type'] = 'application/x-www-form-urlencoded' req.headers['Authorization'] = 'Basic: ' + Base64.strict_encode64("#{client_id}:#{client_secret}") req.body = URI.encode_www_form username: username, password: password, scope: scope, grant_type: 'password' end end
verify_token(token, issuer:, audience:, client_id:)
click to toggle source
validate the token
# File lib/okta/jwt.rb, line 47 def verify_token(token, issuer:, audience:, client_id:) header, payload = token.split('.').first(2).map{|encoded| JSON.parse(Base64.decode64(encoded))} # validate claims raise InvalidToken.new('Invalid issuer') if payload['iss'] != issuer raise InvalidToken.new('Invalid audience') if payload['aud'] != audience raise InvalidToken.new('Invalid client') if !Array(client_id).include?(payload['cid']) raise InvalidToken.new('Token is expired') if payload['exp'].to_i <= Time.now.to_i # validate signature jwk = JSON::JWK.new(get_jwk(header, payload)) JSON::JWT.decode(token, jwk.to_key) end