diff --git a/management/management.gen.go b/management/management.gen.go index 34c76b1e..ee3587ea 100644 --- a/management/management.gen.go +++ b/management/management.gen.go @@ -9144,6 +9144,14 @@ func (r *RefreshToken) GetCreatedAt() time.Time { return *r.CreatedAt } +// GetDevice returns the Device field. +func (r *RefreshToken) GetDevice() *RefreshTokenDevice { + if r == nil { + return nil + } + return r.Device +} + // GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. func (r *RefreshToken) GetExpiresAt() time.Time { if r == nil || r.ExpiresAt == nil { @@ -9168,6 +9176,14 @@ func (r *RefreshToken) GetIdleExpiresAt() time.Time { return *r.IdleExpiresAt } +// GetLastExchangedAt returns the LastExchangedAt field if it's non-nil, zero value otherwise. +func (r *RefreshToken) GetLastExchangedAt() string { + if r == nil || r.LastExchangedAt == nil { + return "" + } + return *r.LastExchangedAt +} + // GetRotating returns the Rotating field if it's non-nil, zero value otherwise. func (r *RefreshToken) GetRotating() bool { if r == nil || r.Rotating == nil { @@ -9197,6 +9213,59 @@ func (r *RefreshToken) String() string { return Stringify(r) } +// GetInitialASN returns the InitialASN field if it's non-nil, zero value otherwise. +func (r *RefreshTokenDevice) GetInitialASN() string { + if r == nil || r.InitialASN == nil { + return "" + } + return *r.InitialASN +} + +// GetInitialIP returns the InitialIP field if it's non-nil, zero value otherwise. +func (r *RefreshTokenDevice) GetInitialIP() string { + if r == nil || r.InitialIP == nil { + return "" + } + return *r.InitialIP +} + +// GetInitialUserAgent returns the InitialUserAgent field if it's non-nil, zero value otherwise. +func (r *RefreshTokenDevice) GetInitialUserAgent() string { + if r == nil || r.InitialUserAgent == nil { + return "" + } + return *r.InitialUserAgent +} + +// GetLastASN returns the LastASN field if it's non-nil, zero value otherwise. +func (r *RefreshTokenDevice) GetLastASN() string { + if r == nil || r.LastASN == nil { + return "" + } + return *r.LastASN +} + +// GetLastIP returns the LastIP field if it's non-nil, zero value otherwise. +func (r *RefreshTokenDevice) GetLastIP() string { + if r == nil || r.LastIP == nil { + return "" + } + return *r.LastIP +} + +// GetLastUserAgent returns the LastUserAgent field if it's non-nil, zero value otherwise. +func (r *RefreshTokenDevice) GetLastUserAgent() string { + if r == nil || r.LastUserAgent == nil { + return "" + } + return *r.LastUserAgent +} + +// String returns a string representation of RefreshTokenDevice. +func (r *RefreshTokenDevice) String() string { + return Stringify(r) +} + // String returns a string representation of RefreshTokenList. func (r *RefreshTokenList) String() string { return Stringify(r) @@ -10375,6 +10444,191 @@ func (s *SentryClientAddon) String() string { return Stringify(s) } +// GetAuthenticatedAt returns the AuthenticatedAt field if it's non-nil, zero value otherwise. +func (s *Session) GetAuthenticatedAt() string { + if s == nil || s.AuthenticatedAt == nil { + return "" + } + return *s.AuthenticatedAt +} + +// GetAuthentication returns the Authentication field. +func (s *Session) GetAuthentication() *SessionAuthentication { + if s == nil { + return nil + } + return s.Authentication +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (s *Session) GetCreatedAt() string { + if s == nil || s.CreatedAt == nil { + return "" + } + return *s.CreatedAt +} + +// GetDevice returns the Device field. +func (s *Session) GetDevice() *SessionDevice { + if s == nil { + return nil + } + return s.Device +} + +// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise. +func (s *Session) GetExpiresAt() string { + if s == nil || s.ExpiresAt == nil { + return "" + } + return *s.ExpiresAt +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (s *Session) GetID() string { + if s == nil || s.ID == nil { + return "" + } + return *s.ID +} + +// GetIdleExpiresAt returns the IdleExpiresAt field if it's non-nil, zero value otherwise. +func (s *Session) GetIdleExpiresAt() string { + if s == nil || s.IdleExpiresAt == nil { + return "" + } + return *s.IdleExpiresAt +} + +// GetLastInteractedAt returns the LastInteractedAt field if it's non-nil, zero value otherwise. +func (s *Session) GetLastInteractedAt() string { + if s == nil || s.LastInteractedAt == nil { + return "" + } + return *s.LastInteractedAt +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (s *Session) GetUpdatedAt() string { + if s == nil || s.UpdatedAt == nil { + return "" + } + return *s.UpdatedAt +} + +// GetUserID returns the UserID field if it's non-nil, zero value otherwise. +func (s *Session) GetUserID() string { + if s == nil || s.UserID == nil { + return "" + } + return *s.UserID +} + +// String returns a string representation of Session. +func (s *Session) String() string { + return Stringify(s) +} + +// String returns a string representation of SessionAuthentication. +func (s *SessionAuthentication) String() string { + return Stringify(s) +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (s *SessionAuthenticationMethod) GetName() string { + if s == nil || s.Name == nil { + return "" + } + return *s.Name +} + +// GetTimestamp returns the Timestamp field if it's non-nil, zero value otherwise. +func (s *SessionAuthenticationMethod) GetTimestamp() string { + if s == nil || s.Timestamp == nil { + return "" + } + return *s.Timestamp +} + +// GetType returns the Type field if it's non-nil, zero value otherwise. +func (s *SessionAuthenticationMethod) GetType() string { + if s == nil || s.Type == nil { + return "" + } + return *s.Type +} + +// String returns a string representation of SessionAuthenticationMethod. +func (s *SessionAuthenticationMethod) String() string { + return Stringify(s) +} + +// GetClientID returns the ClientID field if it's non-nil, zero value otherwise. +func (s *SessionClient) GetClientID() string { + if s == nil || s.ClientID == nil { + return "" + } + return *s.ClientID +} + +// String returns a string representation of SessionClient. +func (s *SessionClient) String() string { + return Stringify(s) +} + +// GetInitialASN returns the InitialASN field if it's non-nil, zero value otherwise. +func (s *SessionDevice) GetInitialASN() string { + if s == nil || s.InitialASN == nil { + return "" + } + return *s.InitialASN +} + +// GetInitialIP returns the InitialIP field if it's non-nil, zero value otherwise. +func (s *SessionDevice) GetInitialIP() string { + if s == nil || s.InitialIP == nil { + return "" + } + return *s.InitialIP +} + +// GetInitialUserAgent returns the InitialUserAgent field if it's non-nil, zero value otherwise. +func (s *SessionDevice) GetInitialUserAgent() string { + if s == nil || s.InitialUserAgent == nil { + return "" + } + return *s.InitialUserAgent +} + +// GetLastASN returns the LastASN field if it's non-nil, zero value otherwise. +func (s *SessionDevice) GetLastASN() string { + if s == nil || s.LastASN == nil { + return "" + } + return *s.LastASN +} + +// GetLastIP returns the LastIP field if it's non-nil, zero value otherwise. +func (s *SessionDevice) GetLastIP() string { + if s == nil || s.LastIP == nil { + return "" + } + return *s.LastIP +} + +// GetLastUserAgent returns the LastUserAgent field if it's non-nil, zero value otherwise. +func (s *SessionDevice) GetLastUserAgent() string { + if s == nil || s.LastUserAgent == nil { + return "" + } + return *s.LastUserAgent +} + +// String returns a string representation of SessionDevice. +func (s *SessionDevice) String() string { + return Stringify(s) +} + // GetExternalURL returns the ExternalURL field if it's non-nil, zero value otherwise. func (s *SharePointClientAddon) GetExternalURL() []string { if s == nil || s.ExternalURL == nil { diff --git a/management/management.gen_test.go b/management/management.gen_test.go index f5cc5c61..32179001 100644 --- a/management/management.gen_test.go +++ b/management/management.gen_test.go @@ -11466,6 +11466,13 @@ func TestRefreshToken_GetCreatedAt(tt *testing.T) { r.GetCreatedAt() } +func TestRefreshToken_GetDevice(tt *testing.T) { + r := &RefreshToken{} + r.GetDevice() + r = nil + r.GetDevice() +} + func TestRefreshToken_GetExpiresAt(tt *testing.T) { var zeroValue time.Time r := &RefreshToken{ExpiresAt: &zeroValue} @@ -11496,6 +11503,16 @@ func TestRefreshToken_GetIdleExpiresAt(tt *testing.T) { r.GetIdleExpiresAt() } +func TestRefreshToken_GetLastExchangedAt(tt *testing.T) { + var zeroValue string + r := &RefreshToken{LastExchangedAt: &zeroValue} + r.GetLastExchangedAt() + r = &RefreshToken{} + r.GetLastExchangedAt() + r = nil + r.GetLastExchangedAt() +} + func TestRefreshToken_GetRotating(tt *testing.T) { var zeroValue bool r := &RefreshToken{Rotating: &zeroValue} @@ -11534,6 +11551,74 @@ func TestRefreshToken_String(t *testing.T) { } } +func TestRefreshTokenDevice_GetInitialASN(tt *testing.T) { + var zeroValue string + r := &RefreshTokenDevice{InitialASN: &zeroValue} + r.GetInitialASN() + r = &RefreshTokenDevice{} + r.GetInitialASN() + r = nil + r.GetInitialASN() +} + +func TestRefreshTokenDevice_GetInitialIP(tt *testing.T) { + var zeroValue string + r := &RefreshTokenDevice{InitialIP: &zeroValue} + r.GetInitialIP() + r = &RefreshTokenDevice{} + r.GetInitialIP() + r = nil + r.GetInitialIP() +} + +func TestRefreshTokenDevice_GetInitialUserAgent(tt *testing.T) { + var zeroValue string + r := &RefreshTokenDevice{InitialUserAgent: &zeroValue} + r.GetInitialUserAgent() + r = &RefreshTokenDevice{} + r.GetInitialUserAgent() + r = nil + r.GetInitialUserAgent() +} + +func TestRefreshTokenDevice_GetLastASN(tt *testing.T) { + var zeroValue string + r := &RefreshTokenDevice{LastASN: &zeroValue} + r.GetLastASN() + r = &RefreshTokenDevice{} + r.GetLastASN() + r = nil + r.GetLastASN() +} + +func TestRefreshTokenDevice_GetLastIP(tt *testing.T) { + var zeroValue string + r := &RefreshTokenDevice{LastIP: &zeroValue} + r.GetLastIP() + r = &RefreshTokenDevice{} + r.GetLastIP() + r = nil + r.GetLastIP() +} + +func TestRefreshTokenDevice_GetLastUserAgent(tt *testing.T) { + var zeroValue string + r := &RefreshTokenDevice{LastUserAgent: &zeroValue} + r.GetLastUserAgent() + r = &RefreshTokenDevice{} + r.GetLastUserAgent() + r = nil + r.GetLastUserAgent() +} + +func TestRefreshTokenDevice_String(t *testing.T) { + var rawJSON json.RawMessage + v := &RefreshTokenDevice{} + if err := json.Unmarshal([]byte(v.String()), &rawJSON); err != nil { + t.Errorf("failed to produce a valid json") + } +} + func TestRefreshTokenList_String(t *testing.T) { var rawJSON json.RawMessage v := &RefreshTokenList{} @@ -13045,6 +13130,240 @@ func TestSentryClientAddon_String(t *testing.T) { } } +func TestSession_GetAuthenticatedAt(tt *testing.T) { + var zeroValue string + s := &Session{AuthenticatedAt: &zeroValue} + s.GetAuthenticatedAt() + s = &Session{} + s.GetAuthenticatedAt() + s = nil + s.GetAuthenticatedAt() +} + +func TestSession_GetAuthentication(tt *testing.T) { + s := &Session{} + s.GetAuthentication() + s = nil + s.GetAuthentication() +} + +func TestSession_GetCreatedAt(tt *testing.T) { + var zeroValue string + s := &Session{CreatedAt: &zeroValue} + s.GetCreatedAt() + s = &Session{} + s.GetCreatedAt() + s = nil + s.GetCreatedAt() +} + +func TestSession_GetDevice(tt *testing.T) { + s := &Session{} + s.GetDevice() + s = nil + s.GetDevice() +} + +func TestSession_GetExpiresAt(tt *testing.T) { + var zeroValue string + s := &Session{ExpiresAt: &zeroValue} + s.GetExpiresAt() + s = &Session{} + s.GetExpiresAt() + s = nil + s.GetExpiresAt() +} + +func TestSession_GetID(tt *testing.T) { + var zeroValue string + s := &Session{ID: &zeroValue} + s.GetID() + s = &Session{} + s.GetID() + s = nil + s.GetID() +} + +func TestSession_GetIdleExpiresAt(tt *testing.T) { + var zeroValue string + s := &Session{IdleExpiresAt: &zeroValue} + s.GetIdleExpiresAt() + s = &Session{} + s.GetIdleExpiresAt() + s = nil + s.GetIdleExpiresAt() +} + +func TestSession_GetLastInteractedAt(tt *testing.T) { + var zeroValue string + s := &Session{LastInteractedAt: &zeroValue} + s.GetLastInteractedAt() + s = &Session{} + s.GetLastInteractedAt() + s = nil + s.GetLastInteractedAt() +} + +func TestSession_GetUpdatedAt(tt *testing.T) { + var zeroValue string + s := &Session{UpdatedAt: &zeroValue} + s.GetUpdatedAt() + s = &Session{} + s.GetUpdatedAt() + s = nil + s.GetUpdatedAt() +} + +func TestSession_GetUserID(tt *testing.T) { + var zeroValue string + s := &Session{UserID: &zeroValue} + s.GetUserID() + s = &Session{} + s.GetUserID() + s = nil + s.GetUserID() +} + +func TestSession_String(t *testing.T) { + var rawJSON json.RawMessage + v := &Session{} + if err := json.Unmarshal([]byte(v.String()), &rawJSON); err != nil { + t.Errorf("failed to produce a valid json") + } +} + +func TestSessionAuthentication_String(t *testing.T) { + var rawJSON json.RawMessage + v := &SessionAuthentication{} + if err := json.Unmarshal([]byte(v.String()), &rawJSON); err != nil { + t.Errorf("failed to produce a valid json") + } +} + +func TestSessionAuthenticationMethod_GetName(tt *testing.T) { + var zeroValue string + s := &SessionAuthenticationMethod{Name: &zeroValue} + s.GetName() + s = &SessionAuthenticationMethod{} + s.GetName() + s = nil + s.GetName() +} + +func TestSessionAuthenticationMethod_GetTimestamp(tt *testing.T) { + var zeroValue string + s := &SessionAuthenticationMethod{Timestamp: &zeroValue} + s.GetTimestamp() + s = &SessionAuthenticationMethod{} + s.GetTimestamp() + s = nil + s.GetTimestamp() +} + +func TestSessionAuthenticationMethod_GetType(tt *testing.T) { + var zeroValue string + s := &SessionAuthenticationMethod{Type: &zeroValue} + s.GetType() + s = &SessionAuthenticationMethod{} + s.GetType() + s = nil + s.GetType() +} + +func TestSessionAuthenticationMethod_String(t *testing.T) { + var rawJSON json.RawMessage + v := &SessionAuthenticationMethod{} + if err := json.Unmarshal([]byte(v.String()), &rawJSON); err != nil { + t.Errorf("failed to produce a valid json") + } +} + +func TestSessionClient_GetClientID(tt *testing.T) { + var zeroValue string + s := &SessionClient{ClientID: &zeroValue} + s.GetClientID() + s = &SessionClient{} + s.GetClientID() + s = nil + s.GetClientID() +} + +func TestSessionClient_String(t *testing.T) { + var rawJSON json.RawMessage + v := &SessionClient{} + if err := json.Unmarshal([]byte(v.String()), &rawJSON); err != nil { + t.Errorf("failed to produce a valid json") + } +} + +func TestSessionDevice_GetInitialASN(tt *testing.T) { + var zeroValue string + s := &SessionDevice{InitialASN: &zeroValue} + s.GetInitialASN() + s = &SessionDevice{} + s.GetInitialASN() + s = nil + s.GetInitialASN() +} + +func TestSessionDevice_GetInitialIP(tt *testing.T) { + var zeroValue string + s := &SessionDevice{InitialIP: &zeroValue} + s.GetInitialIP() + s = &SessionDevice{} + s.GetInitialIP() + s = nil + s.GetInitialIP() +} + +func TestSessionDevice_GetInitialUserAgent(tt *testing.T) { + var zeroValue string + s := &SessionDevice{InitialUserAgent: &zeroValue} + s.GetInitialUserAgent() + s = &SessionDevice{} + s.GetInitialUserAgent() + s = nil + s.GetInitialUserAgent() +} + +func TestSessionDevice_GetLastASN(tt *testing.T) { + var zeroValue string + s := &SessionDevice{LastASN: &zeroValue} + s.GetLastASN() + s = &SessionDevice{} + s.GetLastASN() + s = nil + s.GetLastASN() +} + +func TestSessionDevice_GetLastIP(tt *testing.T) { + var zeroValue string + s := &SessionDevice{LastIP: &zeroValue} + s.GetLastIP() + s = &SessionDevice{} + s.GetLastIP() + s = nil + s.GetLastIP() +} + +func TestSessionDevice_GetLastUserAgent(tt *testing.T) { + var zeroValue string + s := &SessionDevice{LastUserAgent: &zeroValue} + s.GetLastUserAgent() + s = &SessionDevice{} + s.GetLastUserAgent() + s = nil + s.GetLastUserAgent() +} + +func TestSessionDevice_String(t *testing.T) { + var rawJSON json.RawMessage + v := &SessionDevice{} + if err := json.Unmarshal([]byte(v.String()), &rawJSON); err != nil { + t.Errorf("failed to produce a valid json") + } +} + func TestSharePointClientAddon_GetExternalURL(tt *testing.T) { var zeroValue []string s := &SharePointClientAddon{ExternalURL: &zeroValue} diff --git a/management/management.go b/management/management.go index 1ccda18d..d58440f1 100644 --- a/management/management.go +++ b/management/management.go @@ -118,6 +118,12 @@ type Management struct { // EncryptionKey manages Auth0 Encryption Keys. EncryptionKey *EncryptionKeyManager + // RefreshToken manages Auth0 Refresh Tokens. + RefreshToken *RefreshTokenManager + + // Session manages Auth0 Sessions. + Session *SessionManager + url *url.URL basePath string userAgent string @@ -224,6 +230,7 @@ func New(domain string, options ...Option) (*Management, error) { management: m, Vault: (*flowVaultConnectionManager)(&m.common), } - + m.RefreshToken = (*RefreshTokenManager)(&m.common) + m.Session = (*SessionManager)(&m.common) return m, nil } diff --git a/management/refresh_token.go b/management/refresh_token.go new file mode 100644 index 00000000..4d06de80 --- /dev/null +++ b/management/refresh_token.go @@ -0,0 +1,78 @@ +package management + +import ( + "context" + "time" +) + +// RefreshTokenList represents a list of user refresh tokens. +type RefreshTokenList struct { + List + Tokens []*RefreshToken `json:"tokens,omitempty"` +} + +// RefreshToken represents a refresh token. +type RefreshToken struct { + // ID of the refresh token + ID *string `json:"id,omitempty"` + // ID of the user which can be used when interacting with other APIs. + UserID *string `json:"user_id,omitempty"` + // The date and time when the refresh token was created + CreatedAt *time.Time `json:"created_at,omitempty"` + // The date and time when the refresh token was last used + IdleExpiresAt *time.Time `json:"idle_expires_at,omitempty"` + // The date and time when the refresh token will expire + ExpiresAt *time.Time `json:"expires_at,omitempty"` + // Device used while issuing/exchanging the refresh token + Device *RefreshTokenDevice `json:"device,omitempty"` + // ID of the client application granted with this refresh token + ClientID *string `json:"client_id,omitempty"` + // ID of the authenticated session used to obtain this refresh-token + SessionID *string `json:"session_id,omitempty"` + // True if the token is a rotating refresh token + Rotating *bool `json:"rotating,omitempty"` + // A list of the resource server IDs associated to this refresh-token and their granted scopes + ResourceServer []*RefreshTokenResourceServer `json:"resource_servers,omitempty"` + // The date and time when the refresh token was last exchanged + LastExchangedAt *string `json:"last_exchanged_at,omitempty"` +} + +// RefreshTokenDevice represents the device associated with a refresh token. +type RefreshTokenDevice struct { + // First IP address associated with the refresh token + InitialIP *string `json:"initial_ip,omitempty"` + // First autonomous system number associated with the refresh token + InitialASN *string `json:"initial_asn,omitempty"` + // First user agent associated with the refresh token + InitialUserAgent *string `json:"initial_user_agent,omitempty"` + // Last IP address associated with the refresh token + LastIP *string `json:"last_ip,omitempty"` + // Last autonomous system number associated with the refresh token + LastASN *string `json:"last_asn,omitempty"` + // Last user agent associated with the refresh token + LastUserAgent *string `json:"last_user_agent,omitempty"` +} + +// RefreshTokenResourceServer represents the resource server associated with a refresh token. +type RefreshTokenResourceServer struct { + Audience *string `json:"audience,omitempty"` + Scopes *string `json:"scopes,omitempty"` +} + +// RefreshTokenManager manages refresh tokens using the Management API. +type RefreshTokenManager manager + +// Read retrieves a refresh token by its ID. +// +// See: https://auth0.com/docs/api/management/v2#!/Refresh_Tokens/get-refresh-token +func (m *RefreshTokenManager) Read(ctx context.Context, refreshTokenID string, opts ...RequestOption) (r *RefreshToken, err error) { + err = m.management.Request(ctx, "GET", m.management.URI("refresh-tokens", refreshTokenID), &r, opts...) + return +} + +// Delete removes a refresh token by its ID. +// +// See: https://auth0.com/docs/api/management/v2#!/Refresh_Tokens/delete_refresh_token +func (m *RefreshTokenManager) Delete(ctx context.Context, refreshTokenID string, opts ...RequestOption) (err error) { + return m.management.Request(ctx, "DELETE", m.management.URI("refresh-tokens", refreshTokenID), nil, opts...) +} diff --git a/management/refresh_token_test.go b/management/refresh_token_test.go new file mode 100644 index 00000000..7b797199 --- /dev/null +++ b/management/refresh_token_test.go @@ -0,0 +1,65 @@ +package management + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/auth0/go-auth0" +) + +// TestRefreshTokenManager_Read tests the RefreshTokenManager Read method. +// This E2E test is skipped because refresh tokens cannot be created without UI interaction. +func TestRefreshTokenManager_Read(t *testing.T) { + skipTestIfRunningE2E(t) + configureHTTPTestRecordings(t) + + // RecordingNote: This test recording was manually generated to match these details. + // If any changes occur here, the test recording will need manual modification. + expectedRefreshToken := &RefreshToken{ + ID: auth0.String("RefreshTokenID"), + UserID: auth0.String("UserID"), + CreatedAt: auth0.Time(time.Date(2024, 5, 1, 13, 0, 30, 38000000, time.UTC)), + ClientID: auth0.String("CLIENTID"), + Rotating: auth0.Bool(false), + ResourceServer: []*RefreshTokenResourceServer{ + { + Audience: auth0.String("https://go-auth0-dev.eu.auth0.com.us.auth0.com/api/v2/"), + Scopes: auth0.String("openid profile offline_access"), + }, + }, + } + actualRefreshToken, err := api.RefreshToken.Read(context.Background(), expectedRefreshToken.GetID()) + require.NoError(t, err) + require.Equal(t, expectedRefreshToken, actualRefreshToken) +} + +// TestRefreshTokenManager_Delete tests the RefreshTokenManager Delete method. +// This E2E test is skipped because refresh tokens cannot be created without UI interaction. +func TestRefreshTokenManager_Delete(t *testing.T) { + skipTestIfRunningE2E(t) + configureHTTPTestRecordings(t) + + // RecordingNote: This test recording was manually generated to match these details. + // If any changes occur here, the test recording will need manual modification. + expectedRefreshToken := &RefreshToken{ + ID: auth0.String("RefreshTokenID"), + UserID: auth0.String("UserID"), + CreatedAt: auth0.Time(time.Date(2024, 5, 1, 13, 0, 30, 38000000, time.UTC)), + ClientID: auth0.String("CLIENTID"), + Rotating: auth0.Bool(false), + ResourceServer: []*RefreshTokenResourceServer{ + { + Audience: auth0.String("https://go-auth0-dev.eu.auth0.com.us.auth0.com/api/v2/"), + Scopes: auth0.String("openid profile offline_access"), + }, + }, + } + actualRefreshToken, err := api.RefreshToken.Read(context.Background(), expectedRefreshToken.GetID()) + require.NoError(t, err) + + err = api.RefreshToken.Delete(context.Background(), actualRefreshToken.GetID()) + require.NoError(t, err) +} diff --git a/management/session.go b/management/session.go new file mode 100644 index 00000000..423b1e78 --- /dev/null +++ b/management/session.go @@ -0,0 +1,70 @@ +package management + +import "context" + +// Session represents a session Struct. +type Session struct { + ID *string `json:"id,omitempty"` + UserID *string `json:"user_id,omitempty"` + CreatedAt *string `json:"created_at,omitempty"` + UpdatedAt *string `json:"updated_at,omitempty"` + AuthenticatedAt *string `json:"authenticated_at,omitempty"` + IdleExpiresAt *string `json:"idle_expires_at,omitempty"` + ExpiresAt *string `json:"expires_at,omitempty"` + LastInteractedAt *string `json:"last_interacted_at,omitempty"` + Device *SessionDevice `json:"device,omitempty"` + Clients []*SessionClient `json:"clients,omitempty"` + Authentication *SessionAuthentication `json:"authentication,omitempty"` +} + +// SessionDevice represents the device signal details. +type SessionDevice struct { + InitialUserAgent *string `json:"initial_user_agent,omitempty"` + InitialIP *string `json:"initial_ip,omitempty"` + InitialASN *string `json:"initial_asn,omitempty"` + LastUserAgent *string `json:"last_user_agent,omitempty"` + LastIP *string `json:"last_ip,omitempty"` + LastASN *string `json:"last_asn,omitempty"` +} + +// SessionClient represents the client signal details. +type SessionClient struct { + ClientID *string `json:"client_id,omitempty"` +} + +// SessionAuthentication represents the authentication signal details. +type SessionAuthentication struct { + Methods []*SessionAuthenticationMethod `json:"methods,omitempty"` +} + +// SessionAuthenticationMethod represents the authentication signal details. +type SessionAuthenticationMethod struct { + Name *string `json:"name,omitempty"` + Timestamp *string `json:"timestamp,omitempty"` + Type *string `json:"type,omitempty"` +} + +// SessionManager manages sessions using the Management API. +type SessionManager manager + +// Read retrieves a session by its ID. +// +// See: https://auth0.com/docs/api/management/v2#!/Sessions/get_session +func (m *SessionManager) Read(ctx context.Context, sessionID string, opts ...RequestOption) (r *Session, err error) { + err = m.management.Request(ctx, "GET", m.management.URI("sessions", sessionID), &r, opts...) + return +} + +// Delete removes a session by its ID. +// +// See: https://auth0.com/docs/api/management/v2#!/Sessions/delete-session +func (m *SessionManager) Delete(ctx context.Context, sessionID string, opts ...RequestOption) (err error) { + return m.management.Request(ctx, "DELETE", m.management.URI("sessions", sessionID), nil, opts...) +} + +// Revoke revokes a session by its ID. +// +// See: https://auth0.com/docs/api/management/v2#!/Sessions/revoke-session +func (m *SessionManager) Revoke(ctx context.Context, sessionID string, opts ...RequestOption) (err error) { + return m.management.Request(ctx, "POST", m.management.URI("sessions", sessionID, "revoke"), nil, opts...) +} diff --git a/management/session_test.go b/management/session_test.go new file mode 100644 index 00000000..d16ea13c --- /dev/null +++ b/management/session_test.go @@ -0,0 +1,69 @@ +package management + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/auth0/go-auth0" +) + +func TestSessionManager_Read(t *testing.T) { + skipTestIfRunningE2E(t) + configureHTTPTestRecordings(t) + + // RecordingNote: This test recording was manually generated to match these details. + // If any changes occur here, the test recording will need manual modification. + expectedSession := &Session{ + ID: auth0.String("SessionID"), + UserID: auth0.String("UserID"), + CreatedAt: auth0.String("2024-05-01T13:00:30.380Z"), + UpdatedAt: auth0.String("2024-05-01T13:00:30.380Z"), + AuthenticatedAt: auth0.String("2024-05-01T13:00:30.380Z"), + IdleExpiresAt: auth0.String("2024-05-01T13:00:30.380Z"), + ExpiresAt: auth0.String("2024-05-01T13:00:30.380Z"), + LastInteractedAt: auth0.String("2024-05-01T13:00:30.380Z"), + Device: &SessionDevice{ + InitialUserAgent: auth0.String("InitialUserAgent"), + InitialIP: auth0.String("InitialIP"), + InitialASN: auth0.String("InitialASN"), + LastUserAgent: auth0.String("LastUserAgent"), + LastIP: auth0.String("LastIP"), + LastASN: auth0.String("LastASN"), + }, + Clients: []*SessionClient{ + { + ClientID: auth0.String("ClientID"), + }, + }, + Authentication: &SessionAuthentication{ + Methods: []*SessionAuthenticationMethod{ + { + Name: auth0.String("Name"), + Timestamp: auth0.String("2024-05-01T13:00:30.380Z"), + Type: auth0.String("Type"), + }, + }, + }, + } + actualSession, err := api.Session.Read(context.Background(), expectedSession.GetID()) + require.NoError(t, err) + require.Equal(t, expectedSession, actualSession) +} + +func TestSessionManager_Delete(t *testing.T) { + skipTestIfRunningE2E(t) + configureHTTPTestRecordings(t) + + err := api.Session.Delete(context.Background(), "SessionID") + require.NoError(t, err) +} + +func TestSessionManager_Revoke(t *testing.T) { + skipTestIfRunningE2E(t) + configureHTTPTestRecordings(t) + + err := api.Session.Revoke(context.Background(), "SessionID") + require.NoError(t, err) +} diff --git a/management/user.go b/management/user.go index 09cad581..7ceb6611 100644 --- a/management/user.go +++ b/management/user.go @@ -388,31 +388,6 @@ type AuthenticationMethodList struct { Authenticators []*AuthenticationMethod `json:"authenticators,omitempty"` } -// RefreshTokenList represents a list of user refresh tokens. -type RefreshTokenList struct { - List - Tokens []*RefreshToken `json:"tokens,omitempty"` -} - -// RefreshToken represents a refresh token for a user. -type RefreshToken struct { - ID *string `json:"id,omitempty"` - UserID *string `json:"user_id,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - IdleExpiresAt *time.Time `json:"idle_expires_at,omitempty"` - ExpiresAt *time.Time `json:"expires_at,omitempty"` - ClientID *string `json:"client_id,omitempty"` - SessionID *string `json:"session_id,omitempty"` - Rotating *bool `json:"rotating,omitempty"` - ResourceServer []*RefreshTokenResourceServer `json:"resource_servers,omitempty"` -} - -// RefreshTokenResourceServer represents the resource server associated with a refresh token. -type RefreshTokenResourceServer struct { - Audience *string `json:"audience,omitempty"` - Scopes *string `json:"scopes,omitempty"` -} - // UserSessionList represents a list of user sessions. type UserSessionList struct { List diff --git a/test/data/recordings/TestRefreshTokenManager_Delete.yaml b/test/data/recordings/TestRefreshTokenManager_Delete.yaml new file mode 100644 index 00000000..44682e1e --- /dev/null +++ b/test/data/recordings/TestRefreshTokenManager_Delete.yaml @@ -0,0 +1,73 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/1.5.0 + url: https://go-auth0-dev.eu.auth0.com/api/v2/refresh-tokens/RefreshTokenID + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: true + body: '{"id":"RefreshTokenID","user_id":"UserID","created_at":"2024-05-01T13:00:30.038Z","idle_expires_at":null,"expires_at":null,"client_id":"CLIENTID","session_id":null,"rotating":false,"resource_servers":[{"audience":"https://go-auth0-dev.eu.auth0.com.us.auth0.com/api/v2/","scopes":"openid profile offline_access"}]}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 948.362375ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0-SDK/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/refresh-tokens/RefreshTokenID + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 208.2475ms diff --git a/test/data/recordings/TestRefreshTokenManager_Read.yaml b/test/data/recordings/TestRefreshTokenManager_Read.yaml new file mode 100644 index 00000000..30f00654 --- /dev/null +++ b/test/data/recordings/TestRefreshTokenManager_Read.yaml @@ -0,0 +1,38 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/1.5.0 + url: https://go-auth0-dev.eu.auth0.com/api/v2/refresh-tokens/RefreshTokenID + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: true + body: '{"id":"RefreshTokenID","user_id":"UserID","created_at":"2024-05-01T13:00:30.038Z","idle_expires_at":null,"expires_at":null,"client_id":"CLIENTID","session_id":null,"rotating":false,"resource_servers":[{"audience":"https://go-auth0-dev.eu.auth0.com.us.auth0.com/api/v2/","scopes":"openid profile offline_access"}]}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 948.362375ms diff --git a/test/data/recordings/TestSessionManager_Delete.yaml b/test/data/recordings/TestSessionManager_Delete.yaml new file mode 100644 index 00000000..f9b3883b --- /dev/null +++ b/test/data/recordings/TestSessionManager_Delete.yaml @@ -0,0 +1,38 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/1.14.0 + url: https://go-auth0-dev.eu.auth0.com/api/v2/sessions/SessionID + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 2 + uncompressed: false + body: '{}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 202 Accepted + code: 202 + duration: 1.084482375s diff --git a/test/data/recordings/TestSessionManager_Read.yaml b/test/data/recordings/TestSessionManager_Read.yaml new file mode 100644 index 00000000..7116415d --- /dev/null +++ b/test/data/recordings/TestSessionManager_Read.yaml @@ -0,0 +1,38 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/1.14.0 + url: https://go-auth0-dev.eu.auth0.com/api/v2/sessions/SessionID + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: true + body: '{"id":"SessionID","user_id":"UserID","created_at":"2024-05-01T13:00:30.380Z","updated_at":"2024-05-01T13:00:30.380Z","authenticated_at":"2024-05-01T13:00:30.380Z","idle_expires_at":"2024-05-01T13:00:30.380Z","expires_at":"2024-05-01T13:00:30.380Z","last_interacted_at":"2024-05-01T13:00:30.380Z","device":{"initial_user_agent":"InitialUserAgent","initial_ip":"InitialIP","initial_asn":"InitialASN","last_user_agent":"LastUserAgent","last_ip":"LastIP","last_asn":"LastASN"},"clients":[{"client_id":"ClientID"}],"authentication":{"methods":[{"name":"Name","timestamp":"2024-05-01T13:00:30.380Z","type":"Type"}]}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 1.022522208s diff --git a/test/data/recordings/TestSessionManager_Revoke.yaml b/test/data/recordings/TestSessionManager_Revoke.yaml new file mode 100644 index 00000000..04ec0ecd --- /dev/null +++ b/test/data/recordings/TestSessionManager_Revoke.yaml @@ -0,0 +1,38 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/1.14.0 + url: https://go-auth0-dev.eu.auth0.com/api/v2/sessions/SessionID/revoke + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 2 + uncompressed: false + body: '{}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 202 Accepted + code: 202 + duration: 908.509917ms