Skip to content

Commit

Permalink
Add return_to param to UserManagement.get_logout_url (#343)
Browse files Browse the repository at this point in the history
* Backfill test for `.get_logout_url`

* Add `return_to` param to `UserManagement.get_logout_url`

* Also update `Session#get_logout_url`
  • Loading branch information
mthadley authored Jan 15, 2025
1 parent bcbf8f7 commit 1e8e6a5
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 18 deletions.
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

0 comments on commit 1e8e6a5

Please sign in to comment.