diff --git a/pkg/usermanagement/client.go b/pkg/usermanagement/client.go index 13ee87e6..99f20383 100644 --- a/pkg/usermanagement/client.go +++ b/pkg/usermanagement/client.go @@ -498,6 +498,10 @@ type GetInvitationOpts struct { Invitation string } +type FindInvitationByTokenOpts struct { + InvitationToken string +} + // ListInvitations contains the response from the ListInvitations call. type ListInvitationsResponse struct { // List of Invitations @@ -2015,6 +2019,36 @@ func (c *Client) GetInvitation(ctx context.Context, opts GetInvitationOpts) (Inv return body, err } +// FindInvitationByToken fetches an Invitation by its token. +func (c *Client) FindInvitationByToken(ctx context.Context, opts FindInvitationByTokenOpts) (Invitation, error) { + endpoint := fmt.Sprintf("%s/user_management/invitations/by_token/%s", c.Endpoint, opts.InvitationToken) + + req, err := http.NewRequest(http.MethodGet, endpoint, nil) + if err != nil { + return Invitation{}, 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") + + res, err := c.HTTPClient.Do(req) + if err != nil { + return Invitation{}, err + } + defer res.Body.Close() + + if err = workos_errors.TryGetHTTPError(res); err != nil { + return Invitation{}, err + } + + var body Invitation + dec := json.NewDecoder(res.Body) + err = dec.Decode(&body) + + return body, err +} + // ListInvitations gets a list of all of your existing Invitations matching the criteria specified. func (c *Client) ListInvitations(ctx context.Context, opts ListInvitationsOpts) (ListInvitationsResponse, error) { endpoint := fmt.Sprintf( diff --git a/pkg/usermanagement/client_test.go b/pkg/usermanagement/client_test.go index 1f386241..626bf3b2 100644 --- a/pkg/usermanagement/client_test.go +++ b/pkg/usermanagement/client_test.go @@ -2858,6 +2858,89 @@ func getInvitationTestHandler(w http.ResponseWriter, r *http.Request) { w.Write(body) } +func TestFindInvitationByToken(t *testing.T) { + tests := []struct { + scenario string + client *Client + options FindInvitationByTokenOpts + expected Invitation + err bool + }{ + { + scenario: "Request without API Key returns an error", + client: NewClient(""), + err: true, + }, + { + scenario: "Request returns Invitation by token", + client: NewClient("test"), + options: FindInvitationByTokenOpts{InvitationToken: "myToken"}, + expected: Invitation{ + ID: "invitation_123", + Email: "marcelina@foo-corp.com", + State: Pending, + Token: "myToken", + AcceptInvitationUrl: "https://your-app.com/invite?invitation_token=myToken", + ExpiresAt: "2021-06-25T19:07:33.155Z", + CreatedAt: "2021-06-25T19:07:33.155Z", + UpdatedAt: "2021-06-25T19:07:33.155Z", + }, + }, + } + + for _, test := range tests { + t.Run(test.scenario, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(findInvitationByTokenTestHandler)) + defer server.Close() + + client := test.client + client.Endpoint = server.URL + client.HTTPClient = server.Client() + + invitation, err := client.FindInvitationByToken(context.Background(), test.options) + if test.err { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, test.expected, invitation) + }) + } +} + +func findInvitationByTokenTestHandler(w http.ResponseWriter, r *http.Request) { + auth := r.Header.Get("Authorization") + if auth != "Bearer test" { + http.Error(w, "bad auth", http.StatusUnauthorized) + return + } + + var body []byte + var err error + + if r.URL.Path == "/user_management/invitations/by_token/myToken" { + invitation := Invitation{ + ID: "invitation_123", + Email: "marcelina@foo-corp.com", + State: Pending, + Token: "myToken", + AcceptInvitationUrl: "https://your-app.com/invite?invitation_token=myToken", + ExpiresAt: "2021-06-25T19:07:33.155Z", + CreatedAt: "2021-06-25T19:07:33.155Z", + UpdatedAt: "2021-06-25T19:07:33.155Z", + } + body, err = json.Marshal(invitation) + } + + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + w.Write(body) +} + func TestListInvitations(t *testing.T) { tests := []struct { scenario string diff --git a/pkg/usermanagement/usermanagement.go b/pkg/usermanagement/usermanagement.go index 1a60ab97..a6bc987d 100644 --- a/pkg/usermanagement/usermanagement.go +++ b/pkg/usermanagement/usermanagement.go @@ -304,6 +304,13 @@ func GetInvitation( return DefaultClient.GetInvitation(ctx, opts) } +func FindInvitationByToken( + ctx context.Context, + opts FindInvitationByTokenOpts, +) (Invitation, error) { + return DefaultClient.FindInvitationByToken(ctx, opts) +} + func ListInvitations( ctx context.Context, opts ListInvitationsOpts, diff --git a/pkg/usermanagement/usermanagement_test.go b/pkg/usermanagement/usermanagement_test.go index 858bc7f8..82447f5d 100644 --- a/pkg/usermanagement/usermanagement_test.go +++ b/pkg/usermanagement/usermanagement_test.go @@ -661,8 +661,8 @@ func TestUserManagementEnrollAuthFactor(t *testing.T) { } authenticationRes, err := EnrollAuthFactor(context.Background(), EnrollAuthFactorOpts{ - User: "user_01E3JC5F5Z1YJNPGVYWV9SX6GH", - Type: mfa.TOTP, + User: "user_01E3JC5F5Z1YJNPGVYWV9SX6GH", + Type: mfa.TOTP, TOTPSecret: "testSecret", }) @@ -917,6 +917,32 @@ func TestUsersGetInvitation(t *testing.T) { require.Equal(t, expectedResponse, getByIDRes) } +func TestUsersFindInvitationByToken(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(findInvitationByTokenTestHandler)) + defer server.Close() + + DefaultClient = mockClient(server) + SetAPIKey("test") + + expectedResponse := Invitation{ + ID: "invitation_123", + Email: "marcelina@foo-corp.com", + State: Pending, + Token: "myToken", + AcceptInvitationUrl: "https://your-app.com/invite?invitation_token=myToken", + ExpiresAt: "2021-06-25T19:07:33.155Z", + CreatedAt: "2021-06-25T19:07:33.155Z", + UpdatedAt: "2021-06-25T19:07:33.155Z", + } + + getByIDRes, err := FindInvitationByToken(context.Background(), FindInvitationByTokenOpts{ + InvitationToken: "myToken", + }) + + require.NoError(t, err) + require.Equal(t, expectedResponse, getByIDRes) +} + func TestUsersListInvitations(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(listInvitationsTestHandler)) defer server.Close()