Skip to content
Open
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
88 changes: 88 additions & 0 deletions pkg/usermanagement/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,49 @@ type ListIdentitiesOpts struct {
ID string `json:"id"`
}

type Session struct {
// The Object will always be "session".
Object string `json:"object"`
// The unique identifier for the Session.
ID string `json:"id"`
// The unique identifier for the User.
UserID string `json:"user_id"`
// The unique identifier for the Organization.
OrganizationID string `json:"organization_id"`
// The status of the Session.
Status string `json:"status"`
// The authentication method used to create the Session.
AuthMethod string `json:"auth_method"`
// The IP address from which the Session was created.
IPAddress string `json:"ip_address"`
// The user agent from which the Session was created.
UserAgent string `json:"user_agent"`
// The time at which the Session expires.
ExpiresAt string `json:"expires_at"`
// The time at which the Session ended, if applicable.
EndedAt *string `json:"ended_at"`
// The time at which the Session was created.
CreatedAt string `json:"created_at"`
// The time at which the Session was last updated.
UpdatedAt string `json:"updated_at"`
}

type ListSessionsOpts struct {
Limit int `url:"limit"`
Before string `url:"before,omitempty"`
After string `url:"after,omitempty"`
Order Order `url:"order,omitempty"`
}

type ListSessionsResponse struct {
// The Object will always be "list".
Object string `json:"object"`
// List of Sessions
Data []Session `json:"data"`
// Cursor to paginate through the list of Users
ListMetadata common.ListMetadata `json:"list_metadata"`
}

func NewClient(apiKey string) *Client {
return &Client{
APIKey: apiKey,
Expand Down Expand Up @@ -2334,3 +2377,48 @@ func (c *Client) RevokeSession(ctx context.Context, opts RevokeSessionOpts) erro

return nil
}

func (c *Client) ListSessions(ctx context.Context, userID string, opts ListSessionsOpts) (ListSessionsResponse, error) {
req, err := http.NewRequest(
http.MethodGet,
fmt.Sprintf("%s/user_management/users/%s/sessions", c.Endpoint, userID),
nil,
)
if err != nil {
return ListSessionsResponse{}, err
}
req = req.WithContext(ctx)
req.Header.Set("User-Agent", "workos-go/"+workos.Version)
req.Header.Set("Authorization", "Bearer "+c.APIKey)
req.Header.Set("Content-Type", "application/json")

if opts.Limit == 0 {
opts.Limit = ResponseLimit
}

if opts.Order == "" {
opts.Order = Desc
}

queryValues, err := query.Values(opts)
if err != nil {
return ListSessionsResponse{}, err
}

req.URL.RawQuery = queryValues.Encode()
res, err := c.HTTPClient.Do(req)
if err != nil {
return ListSessionsResponse{}, err
}
defer res.Body.Close()

if err = workos_errors.TryGetHTTPError(res); err != nil {
return ListSessionsResponse{}, err
}

var body ListSessionsResponse
dec := json.NewDecoder(res.Body)
err = dec.Decode(&body)

return body, err
}
46 changes: 46 additions & 0 deletions pkg/usermanagement/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3584,6 +3584,52 @@ func RevokeSessionTestHandler(w http.ResponseWriter, r *http.Request) {
w.Write(body)
}

func listSessionsTestHandler(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
if auth != "Bearer test" {
http.Error(w, "bad auth", http.StatusUnauthorized)
return
}

if userAgent := r.Header.Get("User-Agent"); !strings.Contains(userAgent, "workos-go/") {
w.WriteHeader(http.StatusBadRequest)
return
}

body, err := json.Marshal(struct {
ListSessionsResponse
}{
ListSessionsResponse: ListSessionsResponse{
Object: "list",
Data: []Session{
{
Object: "session",
ID: "session_01E4ZCR3C56J083X43JQXF3JK5",
UserID: "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E",
OrganizationID: "org_01E4ZCR3C56J083X43JQXF3JK5",
Status: "active",
AuthMethod: "password",
IPAddress: "192.168.1.1",
UserAgent: "Mozilla/5.0",
ExpiresAt: "2021-07-25T19:07:33.155Z",
CreatedAt: "2021-06-25T19:07:33.155Z",
UpdatedAt: "2021-06-25T19:07:33.155Z",
},
},
ListMetadata: common.ListMetadata{
After: "",
},
},
})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusOK)
w.Write(body)
}

func TestListInvitations_UnmarshalSnakeCaseListMetadata(t *testing.T) {
raw := []byte(`{
"data": [],
Expand Down
8 changes: 8 additions & 0 deletions pkg/usermanagement/usermanagement.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,11 @@ func GetLogoutURL(opts GetLogoutURLOpts) (*url.URL, error) {
func RevokeSession(ctx context.Context, opts RevokeSessionOpts) error {
return DefaultClient.RevokeSession(ctx, opts)
}

func ListSessions(
ctx context.Context,
userID string,
opts ListSessionsOpts,
) (ListSessionsResponse, error) {
return DefaultClient.ListSessions(ctx, userID, opts)
}
36 changes: 36 additions & 0 deletions pkg/usermanagement/usermanagement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1090,3 +1090,39 @@ func TestUsersRevokeSession(t *testing.T) {

require.NoError(t, err)
}

func TestUserManagementListSessions(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(listSessionsTestHandler))

defer server.Close()
userID := "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E"
DefaultClient = mockClient(server)

SetAPIKey("test")
expectedResponse := ListSessionsResponse{
Object: "list",
Data: []Session{
{
Object: "session",
ID: "session_01E4ZCR3C56J083X43JQXF3JK5",
UserID: userID,
OrganizationID: "org_01E4ZCR3C56J083X43JQXF3JK5",
Status: "active",
AuthMethod: "password",
IPAddress: "192.168.1.1",
UserAgent: "Mozilla/5.0",
ExpiresAt: "2021-07-25T19:07:33.155Z",
CreatedAt: "2021-06-25T19:07:33.155Z",
UpdatedAt: "2021-06-25T19:07:33.155Z",
},
},
ListMetadata: common.ListMetadata{
After: "",
},
}

sessionsRes, err := ListSessions(context.Background(), userID, ListSessionsOpts{})

require.NoError(t, err)
require.Equal(t, expectedResponse, sessionsRes)
}