Class: WorkOS::Session
- Inherits:
-
Object
- Object
- WorkOS::Session
- Defined in:
- lib/workos/session.rb
Overview
Wraps a sealed session cookie for authentication, refresh, and logout. Constructed by WorkOS::SessionManager#load; not intended for direct instantiation.
Instance Attribute Summary collapse
-
#cookie_password ⇒ Object
readonly
Returns the value of attribute cookie_password.
-
#seal_data ⇒ Object
readonly
Returns the value of attribute seal_data.
Instance Method Summary collapse
-
#authenticate(include_expired: false, &claim_extractor) ⇒ Hash
Authenticates the user based on the session data.
-
#get_logout_url(return_to: nil) ⇒ Object
Build the WorkOS session-logout URL for the currently authenticated session.
-
#initialize(manager, seal_data:, cookie_password:) ⇒ Session
constructor
A new instance of Session.
- #refresh(organization_id: nil, cookie_password: nil) ⇒ Object
Constructor Details
#initialize(manager, seal_data:, cookie_password:) ⇒ Session
Returns a new instance of Session.
24 25 26 27 28 29 30 |
# File 'lib/workos/session.rb', line 24 def initialize(manager, seal_data:, cookie_password:) raise ArgumentError, "cookie_password is required" if .nil? || .empty? @manager = manager @client = manager.client @seal_data = seal_data @cookie_password = end |
Instance Attribute Details
#cookie_password ⇒ Object (readonly)
Returns the value of attribute cookie_password.
32 33 34 |
# File 'lib/workos/session.rb', line 32 def @cookie_password end |
#seal_data ⇒ Object (readonly)
Returns the value of attribute seal_data.
32 33 34 |
# File 'lib/workos/session.rb', line 32 def seal_data @seal_data end |
Instance Method Details
#authenticate(include_expired: false, &claim_extractor) ⇒ Hash
Authenticates the user based on the session data
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/workos/session.rb', line 38 def authenticate(include_expired: false, &claim_extractor) return SessionManager::AuthError.new(authenticated: false, reason: SessionManager::NO_SESSION_COOKIE_PROVIDED) if @seal_data.nil? || @seal_data.empty? session = begin @manager.unseal_data(@seal_data, @cookie_password) rescue ArgumentError, OpenSSL::Cipher::CipherError return SessionManager::AuthError.new(authenticated: false, reason: SessionManager::INVALID_SESSION_COOKIE) end return SessionManager::AuthError.new(authenticated: false, reason: SessionManager::INVALID_SESSION_COOKIE) unless session.is_a?(Hash) && session["access_token"] decoded = begin @manager.decode_jwt(session["access_token"], verify_expiration: !include_expired) rescue JWT::ExpiredSignature return SessionManager::AuthError.new(authenticated: false, reason: SessionManager::EXPIRED_JWT) rescue JWT::IncorrectAlgorithm return SessionManager::AuthError.new(authenticated: false, reason: SessionManager::INVALID_JWT_ALGORITHM) rescue JWT::VerificationError return SessionManager::AuthError.new(authenticated: false, reason: SessionManager::INVALID_JWT_SIGNATURE) rescue JWT::DecodeError return SessionManager::AuthError.new(authenticated: false, reason: SessionManager::INVALID_JWT) end is_expired = decoded["exp"] && decoded["exp"] < Time.now.to_i SessionManager::AuthSuccess.new( authenticated: !is_expired, reason: is_expired ? SessionManager::EXPIRED_JWT : nil, session_id: decoded["sid"], organization_id: decoded["org_id"], role: decoded["role"], roles: decoded["roles"], permissions: decoded["permissions"], entitlements: decoded["entitlements"], user: session["user"], impersonator: session["impersonator"], feature_flags: decoded["feature_flags"], custom_claims: claim_extractor&.call(decoded) ) end |
#get_logout_url(return_to: nil) ⇒ Object
Build the WorkOS session-logout URL for the currently authenticated session. Requires #authenticate to succeed (so we have the session_id).
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/workos/session.rb', line 124 def get_logout_url(return_to: nil) result = authenticate raise WorkOS::Error.new(message: "Failed to extract session ID for logout URL: #{result.reason}") if result.is_a?(SessionManager::AuthError) base = @client.base_url params = {"session_id" => result.session_id} params["return_to"] = return_to if return_to uri = URI.join(base, "/user_management/sessions/logout") uri.query = URI.encode_www_form(params) uri.to_s end |
#refresh(organization_id: nil, cookie_password: nil) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/workos/session.rb', line 78 def refresh(organization_id: nil, cookie_password: nil) effective_password = || @cookie_password session = begin @manager.unseal_data(@seal_data, effective_password) rescue ArgumentError, OpenSSL::Cipher::CipherError return SessionManager::RefreshError.new(authenticated: false, reason: SessionManager::INVALID_SESSION_COOKIE) end return SessionManager::RefreshError.new(authenticated: false, reason: SessionManager::INVALID_SESSION_COOKIE) unless session.is_a?(Hash) && session["refresh_token"] # Uses auth: true (Bearer token) to match authenticate_with_refresh_token. # client_id is included in the body as required by the OAuth2 token exchange. body = { "grant_type" => "refresh_token", "client_id" => @client.client_id, "refresh_token" => session["refresh_token"], "session" => {"seal_session" => true, "cookie_password" => effective_password} } body["organization_id"] = organization_id if organization_id response = @client.request(method: :post, path: "/user_management/authenticate", auth: true, body: body) auth_response = JSON.parse(response.body) sealed = auth_response["sealed_session"].to_s @seal_data = sealed @cookie_password = effective_password decoded = @manager.decode_jwt(auth_response["access_token"]) SessionManager::RefreshSuccess.new( authenticated: true, sealed_session: sealed, session_id: decoded["sid"], organization_id: decoded["org_id"], role: decoded["role"], roles: decoded["roles"], permissions: decoded["permissions"], entitlements: decoded["entitlements"], user: auth_response["user"], impersonator: auth_response["impersonator"], feature_flags: decoded["feature_flags"] ) rescue WorkOS::AuthenticationError, WorkOS::InvalidRequestError => e SessionManager::RefreshError.new(authenticated: false, reason: e.) end |