Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions lib/workos/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,17 @@ def refresh(options = nil)
# rubocop:enable Metrics/PerceivedComplexity

# Returns a URL to redirect the user to for logging out
# @param return_to [String] The URL to redirect the user to after logging out
# @return [String] The URL to redirect the user to for logging out
# rubocop:disable Naming/AccessorMethodName
def get_logout_url
def get_logout_url(return_to: nil)
auth_response = authenticate

unless auth_response[:authenticated]
raise "Failed to extract session ID for logout URL: #{auth_response[:reason]}"
end

@user_management.get_logout_url(session_id: auth_response[:session_id])
@user_management.get_logout_url(session_id: auth_response[:session_id], return_to: return_to)
end
# rubocop:enable Naming/AccessorMethodName

# Encrypts and seals data using AES-256-GCM
# @param data [Hash] The data to seal
Expand Down
8 changes: 6 additions & 2 deletions lib/workos/user_management.rb
Original file line number Diff line number Diff line change
Expand Up @@ -530,13 +530,17 @@ def authenticate_with_email_verification(
#
# @param [String] session_id The session ID can be found in the `sid`
# claim of the access token
# @param [String] return_to The URL to redirect the user to after logging out
#
# @return String
def get_logout_url(session_id:)
def get_logout_url(session_id:, return_to: nil)
params = { session_id: session_id }
params[:return_to] = return_to if return_to

URI::HTTPS.build(
host: WorkOS.config.api_hostname,
path: '/user_management/sessions/logout',
query: "session_id=#{session_id}",
query: URI.encode_www_form(params),
).to_s
end

Expand Down
42 changes: 30 additions & 12 deletions spec/lib/workos/session_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# frozen_string_literal: true

describe WorkOS::Session do
let(:user_management) { instance_double('UserManagement') }
let(:client_id) { 'test_client_id' }
let(:cookie_password) { 'test_very_long_cookie_password__' }
let(:session_data) { 'test_session_data' }
Expand All @@ -10,11 +9,16 @@
let(:jwk) { JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), { kid: 'sso_oidc_key_pair_123', use: 'sig', alg: 'RS256' }) }

before do
allow(user_management).to receive(:get_jwks_url).with(client_id).and_return(jwks_url)
allow(Net::HTTP).to receive(:get).and_return(jwks_hash)
end

describe 'initialize' do
let(:user_management) { instance_double('UserManagement') }

before do
allow(user_management).to receive(:get_jwks_url).with(client_id).and_return(jwks_url)
end

it 'raises an error if cookie_password is nil or empty' do
expect do
WorkOS::Session.new(
Expand Down Expand Up @@ -52,6 +56,7 @@
end

describe '.authenticate' do
let(:user_management) { instance_double('UserManagement') }
let(:valid_access_token) do
payload = {
sid: 'session_id',
Expand All @@ -71,6 +76,10 @@
}, cookie_password,)
end

before do
allow(user_management).to receive(:get_jwks_url).with(client_id).and_return(jwks_url)
end

it 'returns NO_SESSION_COOKIE_PROVIDED if session_data is nil' do
session = WorkOS::Session.new(
user_management: user_management,
Expand Down Expand Up @@ -135,11 +144,13 @@
end

describe '.refresh' do
let(:user_management) { instance_double('UserManagement') }
let(:refresh_token) { 'test_refresh_token' }
let(:session_data) { WorkOS::Session.seal_data({ refresh_token: refresh_token, user: 'user' }, cookie_password) }
let(:auth_response) { double('AuthResponse', sealed_session: 'new_sealed_session') }

before do
allow(user_management).to receive(:get_jwks_url).with(client_id).and_return(jwks_url)
allow(user_management).to receive(:authenticate_with_refresh_token).and_return(auth_response)
end

Expand Down Expand Up @@ -173,26 +184,33 @@

describe '.get_logout_url' do
let(:session) do
WorkOS::Session.new(
user_management: user_management,
client_id: client_id,
session_data: session_data,
cookie_password: cookie_password,
)
end
WorkOS::Session.new(
user_management: WorkOS::UserManagement,
client_id: client_id,
session_data: session_data,
cookie_password: cookie_password,
)
end

context 'when authentication is successful' do
before do
allow(session).to receive(:authenticate).and_return({
authenticated: true,
session_id: 'session_id',
session_id: 'session_123abc',
reason: nil,
})
allow(user_management).to receive(:get_logout_url).with(session_id: 'session_id').and_return('https://example.com/logout')
end

it 'returns the logout URL' do
expect(session.get_logout_url).to eq('https://example.com/logout')
expect(session.get_logout_url).to eq('https://api.workos.com/user_management/sessions/logout?session_id=session_123abc')
end

context 'when given a return_to URL' do
it 'returns the logout URL with the return_to parameter' do
expect(session.get_logout_url(return_to: 'https://example.com/signed-out')).to eq(
'https://api.workos.com/user_management/sessions/logout?session_id=session_123abc&return_to=https%3A%2F%2Fexample.com%2Fsigned-out',
)
end
end
end

Expand Down
21 changes: 21 additions & 0 deletions spec/lib/workos/user_management_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1441,4 +1441,25 @@
end
end
end

describe '.get_logout_url' do
it 'returns a logout url for the given session ID' do
result = described_class.get_logout_url(
session_id: 'session_01HRX85ATNADY1GQ053AHRFFN6',
)

expect(result).to eq 'https://api.workos.com/user_management/sessions/logout?session_id=session_01HRX85ATNADY1GQ053AHRFFN6'
end

context 'when a `return_to` is given' do
it 'returns a logout url with the `return_to` query parameter' do
result = described_class.get_logout_url(
session_id: 'session_01HRX85ATNADY1GQ053AHRFFN6',
return_to: 'https://example.com/signed-out',
)

expect(result).to eq 'https://api.workos.com/user_management/sessions/logout?session_id=session_01HRX85ATNADY1GQ053AHRFFN6&return_to=https%3A%2F%2Fexample.com%2Fsigned-out'
end
end
end
end
Loading