Skip to content

Commit ce5fae7

Browse files
authored
Add list sessions to user management (#415)
Implementing the 'List sessions' API [1] providing a way to get the list of a users sessions data and a clean API to revoke them using the existing user management API. Note that due to how this gem already has a `Session` class at the root level, which provides the 'session helpers' [2] I nested this in the `UserManagement` namespace so as not to conflict or require a breaking change. 1: https://workos.com/docs/reference/authkit/session/list 2: https://workos.com/docs/reference/authkit/session-helpers
1 parent 27139bd commit ce5fae7

File tree

4 files changed

+170
-0
lines changed

4 files changed

+170
-0
lines changed

lib/workos/user_management.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ module WorkOS
77
# The UserManagement module provides convenience methods for working with the
88
# WorkOS User platform. You'll need a valid API key.
99
module UserManagement
10+
autoload :Session, 'workos/user_management/session'
11+
1012
module Types
1113
# The ProviderEnum is a declaration of a
1214
# fixed set of values for User Management Providers.
@@ -740,6 +742,40 @@ def list_auth_factors(user_id:)
740742
)
741743
end
742744

745+
# Get all sessions for a user
746+
#
747+
# @param [String] user_id The id for the user.
748+
# @param [Hash] options
749+
# @option options [String] limit Maximum number of records to return.
750+
# @option options [String] order The order in which to paginate records
751+
# @option options [String] before Pagination cursor to receive records
752+
# before a provided Session ID.
753+
# @option options [String] after Pagination cursor to receive records
754+
# after a provided Session ID.
755+
#
756+
# @return [WorkOS::Types::ListStruct<WorkOS::UserManagement::Session>]
757+
def list_sessions(user_id:, options: {})
758+
options[:order] ||= 'desc'
759+
response = execute_request(
760+
request: get_request(
761+
path: "/user_management/users/#{user_id}/sessions",
762+
auth: true,
763+
params: options,
764+
),
765+
)
766+
767+
parsed_response = JSON.parse(response.body)
768+
769+
sessions = parsed_response['data'].map do |session|
770+
::WorkOS::UserManagement::Session.new(session.to_json)
771+
end
772+
773+
WorkOS::Types::ListStruct.new(
774+
data: sessions,
775+
list_metadata: parsed_response['list_metadata'],
776+
)
777+
end
778+
743779
# Gets an email verification object
744780
#
745781
# @param [String] id The unique ID of the EmailVerification object.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# frozen_string_literal: true
2+
3+
module WorkOS
4+
module UserManagement
5+
# The Session class provides a lightweight wrapper around
6+
# a WorkOS Session resource. This class is not meant to be instantiated
7+
# in user space, and is instantiated internally but exposed.
8+
class Session
9+
include HashProvider
10+
attr_accessor :id, :object, :user_id, :organization_id, :status, :auth_method,
11+
:ip_address, :user_agent, :expires_at, :ended_at, :created_at, :updated_at
12+
13+
# rubocop:disable Metrics/AbcSize
14+
def initialize(json)
15+
hash = JSON.parse(json, symbolize_names: true)
16+
17+
@id = hash[:id]
18+
@object = hash[:object]
19+
@user_id = hash[:user_id]
20+
@organization_id = hash[:organization_id]
21+
@status = hash[:status]
22+
@auth_method = hash[:auth_method]
23+
@ip_address = hash[:ip_address]
24+
@user_agent = hash[:user_agent]
25+
@expires_at = hash[:expires_at]
26+
@ended_at = hash[:ended_at]
27+
@created_at = hash[:created_at]
28+
@updated_at = hash[:updated_at]
29+
end
30+
# rubocop:enable Metrics/AbcSize
31+
32+
def to_json(*)
33+
{
34+
id: id,
35+
object: object,
36+
user_id: user_id,
37+
organization_id: organization_id,
38+
status: status,
39+
auth_method: auth_method,
40+
ip_address: ip_address,
41+
user_agent: user_agent,
42+
expires_at: expires_at,
43+
ended_at: ended_at,
44+
created_at: created_at,
45+
updated_at: updated_at,
46+
}
47+
end
48+
49+
# Revoke this session
50+
#
51+
# @return [Bool] - returns `true` if successful
52+
def revoke
53+
WorkOS::UserManagement.revoke_session(session_id: id)
54+
end
55+
end
56+
end
57+
end

spec/lib/workos/user_management_spec.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,6 +1797,45 @@
17971797
end
17981798
end
17991799

1800+
describe '.list_sessions' do
1801+
context 'with a valid user_id' do
1802+
it 'returns a list of sessions' do
1803+
VCR.use_cassette('user_management/list_sessions/valid') do
1804+
result = described_class.list_sessions(
1805+
user_id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
1806+
)
1807+
1808+
expect(result.data).to be_an(Array)
1809+
expect(result.data.first).to be_a(WorkOS::UserManagement::Session)
1810+
expect(result.data.first.id).to eq('session_01H96FETXGTW2S0V5V9XPSM6H44')
1811+
expect(result.data.first.status).to eq('active')
1812+
expect(result.data.first.auth_method).to eq('password')
1813+
end
1814+
end
1815+
1816+
it 'returns sessions that can be revoked' do
1817+
VCR.use_cassette('user_management/list_sessions/valid') do
1818+
result = described_class.list_sessions(
1819+
user_id: 'user_01H7TVSKS45SDHN5V9XPSM6H44',
1820+
)
1821+
session = result.data.first
1822+
1823+
expect(described_class).to receive(:post_request) do |options|
1824+
expect(options[:path]).to eq('/user_management/sessions/revoke')
1825+
expect(options[:body]).to eq({ session_id: 'session_01H96FETXGTW2S0V5V9XPSM6H44' })
1826+
expect(options[:auth]).to be true
1827+
end.and_return(double('request'))
1828+
1829+
expect(described_class).to receive(:execute_request).and_return(
1830+
double('response', is_a?: true),
1831+
)
1832+
1833+
expect(session.revoke).to be true
1834+
end
1835+
end
1836+
end
1837+
end
1838+
18001839
describe '.get_logout_url' do
18011840
it 'returns a logout url for the given session ID' do
18021841
result = described_class.get_logout_url(

spec/support/fixtures/vcr_cassettes/user_management/list_sessions/valid.yml

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)