management/user.go
package management
import (
"encoding/json"
"net/http"
"reflect"
"strconv"
"time"
)
// User represents an Auth0 user resource
//
// See: https://auth0.com/docs/users
type User struct {
// The users identifier.
ID *string `json:"user_id,omitempty"`
// The connection the user belongs to.
Connection *string `json:"connection,omitempty"`
// The user's email
Email *string `json:"email,omitempty"`
// The users name
Name *string `json:"name,omitempty"`
// The users given name
GivenName *string `json:"given_name,omitempty"`
// The users family name
FamilyName *string `json:"family_name,omitempty"`
// The user's username. Only valid if the connection requires a username
Username *string `json:"username,omitempty"`
// The user's nickname
Nickname *string `json:"nickname,omitempty"`
// The screen name, handle, or alias that this user identifies themselves with
ScreenName *string `json:"screen_name,omitempty"`
// The user-defined UTF-8 string describing their account
Description *string `json:"description,omitempty"`
// The user-defined location for this account’s profile
Location *string `json:"location,omitempty"`
// The user's password (mandatory for non SMS connections)
Password *string `json:"password,omitempty"`
// The user's phone number (following the E.164 recommendation), only valid
// for users to be added to SMS connections.
PhoneNumber *string `json:"phone_number,omitempty"`
// The time the user is created.
CreatedAt *time.Time `json:"created_at,omitempty"`
// The last time the user is updated.
UpdatedAt *time.Time `json:"updated_at,omitempty"`
// The last time the user has logged in.
LastLogin *time.Time `json:"last_login,omitempty"`
// UserMetadata holds data that the user has read/write access to (e.g.
// color_preference, blog_url, etc).
UserMetadata map[string]interface{} `json:"user_metadata,omitempty"`
// Identities is a list of user identities for when accounts are linked.
Identities []*UserIdentity `json:"identities,omitempty"`
// True if the user's email is verified, false otherwise. If it is true then
// the user will not receive a verification email, unless verify_email: true
// was specified.
EmailVerified *bool `json:"-"`
// If true, the user will receive a verification email after creation, even
// if created with email_verified set to true. If false, the user will not
// receive a verification email, even if created with email_verified set to
// false. If unspecified, defaults to the behavior determined by the value
// of email_verified.
VerifyEmail *bool `json:"verify_email,omitempty"`
// True if the user's phone number is verified, false otherwise. When the
// user is added to a SMS connection, they will not receive an verification
// SMS if this is true.
PhoneVerified *bool `json:"phone_verified,omitempty"`
// AppMetadata holds data that the user has read-only access to (e.g. roles,
// permissions, vip, etc).
AppMetadata map[string]interface{} `json:"app_metadata,omitempty"`
// The user's picture url
Picture *string `json:"picture,omitempty"`
// A URL provided by the user in association with their profile
URL *string `json:"url,omitempty"`
// True if the user is blocked from the application, false if the user is enabled
Blocked *bool `json:"blocked,omitempty"`
// Last IP address from which this user logged in. Read only, cannot be modified.
LastIP *string `json:"last_ip,omitempty"`
// Total number of logins this user has performed. Read only, cannot be modified.
LoginsCount *int64 `json:"logins_count,omitempty"`
}
// UnmarshalJSON is a custom deserializer for the User type.
//
// We have to use a custom one due to possible inconsistencies in value types.
func (u *User) UnmarshalJSON(b []byte) error {
type user User
type userAlias struct {
*user
RawEmailVerified interface{} `json:"email_verified,omitempty"`
}
alias := &userAlias{(*user)(u), nil}
err := json.Unmarshal(b, alias)
if err != nil {
return err
}
if alias.RawEmailVerified != nil {
var emailVerified bool
switch rawEmailVerified := alias.RawEmailVerified.(type) {
case bool:
emailVerified = rawEmailVerified
case string:
emailVerified, err = strconv.ParseBool(rawEmailVerified)
if err != nil {
return err
}
default:
panic(reflect.TypeOf(rawEmailVerified))
}
alias.EmailVerified = &emailVerified
}
return nil
}
func (u *User) MarshalJSON() ([]byte, error) {
type user User
type userAlias struct {
*user
RawEmailVerified interface{} `json:"email_verified,omitempty"`
}
alias := &userAlias{user: (*user)(u)}
if u.EmailVerified != nil {
alias.RawEmailVerified = u.EmailVerified
}
return json.Marshal(alias)
}
// UserIdentityLink contains the data needed for linking an identity to a given user.
type UserIdentityLink struct {
// Connection id of the secondary user account being linked when more than one auth0 database provider exists.
ConnectionID *string `json:"connection_id,omitempty"`
// Secondary account user id.
UserID *string `json:"user_id,omitempty"`
// Identity provider of the secondary user account being linked.
Provider *string `json:"provider,omitempty"`
// LinkWith requires the authenticated primary account's JWT in the Authorization header.
// Must be a JWT for the secondary account being linked. If sending this parameter,
// provider, user_id, and connection_id must not be sent.
LinkWith *string `json:"link_with,omitempty"`
}
type UserIdentity struct {
Connection *string `json:"connection,omitempty"`
UserID *string `json:"-"`
Provider *string `json:"provider,omitempty"`
IsSocial *bool `json:"isSocial,omitempty"`
AccessToken *string `json:"access_token,omitempty"`
AccessTokenSecret *string `json:"access_token_secret,omitempty"`
RefreshToken *string `json:"refresh_token,omitempty"`
}
// UnmarshalJSON is a custom deserializer for the UserIdentity type.
//
// We have to use a custom one due to a bug in the Auth0 Management API which
// might return a number for `user_id` instead of a string.
//
// See https://community.auth0.com/t/users-user-id-returns-inconsistent-type-for-identities-user-id/39236
func (i *UserIdentity) UnmarshalJSON(b []byte) error {
type userIdentity UserIdentity
type userIdentityAlias struct {
*userIdentity
RawUserID interface{} `json:"user_id,omitempty"`
}
alias := &userIdentityAlias{(*userIdentity)(i), nil}
err := json.Unmarshal(b, alias)
if err != nil {
return err
}
if alias.RawUserID != nil {
var id string
switch rawID := alias.RawUserID.(type) {
case string:
id = rawID
case float64:
id = strconv.Itoa(int(rawID))
default:
panic(reflect.TypeOf(rawID))
}
alias.UserID = &id
}
return nil
}
func (i *UserIdentity) MarshalJSON() ([]byte, error) {
type userIdentity UserIdentity
type userIdentityAlias struct {
*userIdentity
RawUserID interface{} `json:"user_id,omitempty"`
}
alias := &userIdentityAlias{userIdentity: (*userIdentity)(i)}
if i.UserID != nil {
alias.RawUserID = i.UserID
}
return json.Marshal(alias)
}
type userBlock struct {
BlockedFor []*UserBlock `json:"blocked_for,omitempty"`
}
type UserBlock struct {
Identifier *string `json:"identifier,omitempty"`
IP *string `json:"ip,omitempty"`
}
type UserRecoveryCode struct {
RecoveryCode *string `json:"recovery_code,omitempty"`
}
// UserEnrollment contains information about the Guardian enrollments for the user
type UserEnrollment struct {
// Authentication method for this enrollment. Can be `authentication`, `guardian`, or `sms`.
AuthMethod *string `json:"auth_method,omitempty"`
// Start date and time of this enrollment.
EnrolledAt *time.Time `json:"enrolled_at,omitempty"`
// ID of this enrollment.
ID *string `json:"id,omitempty"`
// Device identifier (usually phone identifier) of this enrollment.
Identifier *string `json:"identifier,omitempty"`
// Last authentication date and time of this enrollment.
LastAuth *time.Time `json:"last_auth,omitempty"`
// Name of enrollment (usually phone number).
Name *string `json:"name,omitempty"`
// Phone number for this enrollment.
PhoneNumber *string `json:"phone_number,omitempty"`
// Status of this enrollment. Can be `pending` or `confirmed`.
Status *string `json:"status,omitempty"`
// Type of enrollment.
Type *string `json:"type,omitempty"`
}
// UserList is an envelope struct which is used when calling List() or Search()
// methods.
//
// It holds metadata such as the total result count, starting offset and limit.
type UserList struct {
List
Users []*User `json:"users"`
}
// UserManager manages Auth0 User resources.
type UserManager struct {
*Management
}
// newUserManager returns a new instance of a user manager.
func newUserManager(m *Management) *UserManager {
return &UserManager{m}
}
// Create a new user. It works only for database and passwordless connections.
//
// The samples on the right show you every attribute that could be used. The
// attribute connection is always mandatory but depending on the type of
// connection you are using there could be others too. For instance, database
// connections require `email` and `password`.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/post_users
func (m *UserManager) Create(u *User, opts ...RequestOption) error {
return m.Request("POST", m.URI("users"), u, opts...)
}
// Read user details for a given user_id.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/get_users_by_id
func (m *UserManager) Read(id string, opts ...RequestOption) (u *User, err error) {
err = m.Request("GET", m.URI("users", id), &u, opts...)
return
}
// Update user.
//
// The following attributes can be updated at the root level:
//
// - `app_metadata`
// - `blocked`
// - `email`
// - `email_verified`
// - `family_name`
// - `given_name`
// - `name`
// - `nickname`
// - `password`
// - `phone_number`
// - `phone_verified`
// - `picture`
// - `username`
// - `user_metadata`
// - `verify_email`
//
// See: https://auth0.com/docs/api/management/v2#!/Users/patch_users_by_id
func (m *UserManager) Update(id string, u *User, opts ...RequestOption) (err error) {
return m.Request("PATCH", m.URI("users", id), u, opts...)
}
// Delete a single user based on its id.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/delete_users_by_id
func (m *UserManager) Delete(id string, opts ...RequestOption) (err error) {
return m.Request("DELETE", m.URI("users", id), nil, opts...)
}
// List all users. This method forces the `include_totals` option.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/get_users
func (m *UserManager) List(opts ...RequestOption) (ul *UserList, err error) {
err = m.Request("GET", m.URI("users"), &ul, applyListDefaults(opts))
return
}
// Search is an alias for List.
func (m *UserManager) Search(opts ...RequestOption) (ul *UserList, err error) {
return m.List(opts...)
}
// ListByEmail retrieves all users matching a given email.
//
// If Auth0 is the identify provider (idP), the email address associated with a
// user is saved in lower case, regardless of how you initially provided it.
// For example, if you register a user as JohnSmith@example.com, Auth0 saves the
// user's email as johnsmith@example.com.
//
// In cases where Auth0 is not the idP, the `email` is stored based on the rules
// of idP, so make sure the search is made using the correct capitalization.
//
// When using this endpoint, make sure that you are searching for users via
// email addresses using the correct case.
//
// See: https://auth0.com/docs/api/management/v2#!/Users_By_Email/get_users_by_email
func (m *UserManager) ListByEmail(email string, opts ...RequestOption) (us []*User, err error) {
opts = append(opts, Parameter("email", email))
err = m.Request("GET", m.URI("users-by-email"), &us, opts...)
return
}
// Roles lists all roles associated with a user.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/get_user_roles
func (m *UserManager) Roles(id string, opts ...RequestOption) (r *RoleList, err error) {
err = m.Request("GET", m.URI("users", id, "roles"), &r, applyListDefaults(opts))
return
}
// AssignRoles assigns roles to a user.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/post_user_roles
func (m *UserManager) AssignRoles(id string, roles []*Role, opts ...RequestOption) error {
r := make(map[string][]*string)
r["roles"] = make([]*string, len(roles))
for i, role := range roles {
r["roles"][i] = role.ID
}
return m.Request("POST", m.URI("users", id, "roles"), &r, opts...)
}
// RemoveRoles removes any roles associated to a user.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/delete_user_roles
func (m *UserManager) RemoveRoles(id string, roles []*Role, opts ...RequestOption) error {
r := make(map[string][]*string)
r["roles"] = make([]*string, len(roles))
for i, role := range roles {
r["roles"][i] = role.ID
}
return m.Request("DELETE", m.URI("users", id, "roles"), &r, opts...)
}
// Permissions lists the permissions associated to the user.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/get_permissions
func (m *UserManager) Permissions(id string, opts ...RequestOption) (p *PermissionList, err error) {
err = m.Request("GET", m.URI("users", id, "permissions"), &p, applyListDefaults(opts))
return
}
// AssignPermissions assigns permissions to the user.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/post_permissions
func (m *UserManager) AssignPermissions(id string, permissions []*Permission, opts ...RequestOption) error {
p := make(map[string][]*Permission)
p["permissions"] = permissions
return m.Request("POST", m.URI("users", id, "permissions"), &p, opts...)
}
// RemovePermissions removes any permissions associated to a user.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/delete_permissions
func (m *UserManager) RemovePermissions(id string, permissions []*Permission, opts ...RequestOption) error {
p := make(map[string][]*Permission)
p["permissions"] = permissions
return m.Request("DELETE", m.URI("users", id, "permissions"), &p, opts...)
}
// Blocks retrieves a list of blocked IP addresses of a particular user using the
// user ID.
//
// See: https://auth0.com/docs/api/management/v2#!/User_Blocks/get_user_blocks_by_id
func (m *UserManager) Blocks(id string, opts ...RequestOption) ([]*UserBlock, error) {
b := new(userBlock)
err := m.Request("GET", m.URI("user-blocks", id), &b, opts...)
return b.BlockedFor, err
}
// Blocks retrieves a list of blocked IP addresses of a particular user using
// any of the user identifiers: username, phone number or email.
//
// See: https://auth0.com/docs/api/management/v2#!/User_Blocks/get_user_blocks
func (m *UserManager) BlocksByIdentifier(identifier string, opts ...RequestOption) ([]*UserBlock, error) {
b := new(userBlock)
opts = append(opts, Parameter("identifier", identifier))
err := m.Request("GET", m.URI("user-blocks"), &b, opts...)
return b.BlockedFor, err
}
// Unblock a user that was blocked due to an excessive amount of incorrectly
// provided credentials using the user ID.
//
// Note: This endpoint does not unblock users that were blocked by admins.
//
// See: https://auth0.com/docs/api/management/v2#!/User_Blocks/delete_user_blocks_by_id
func (m *UserManager) Unblock(id string, opts ...RequestOption) error {
return m.Request("DELETE", m.URI("user-blocks", id), nil, opts...)
}
// Unblock a user that was blocked due to an excessive amount of incorrectly
// provided credentials using any of the user identifiers: username, phone number or email.
//
// Note: This endpoint does not unblock users that were blocked by admins.
//
// See: https://auth0.com/docs/api/management/v2#!/User_Blocks/delete_user_blocks
func (m *UserManager) UnblockByIdentifier(identifier string, opts ...RequestOption) error {
opts = append(opts, Parameter("identifier", identifier))
return m.Request("DELETE", m.URI("user-blocks"), nil, opts...)
}
// Enrollments retrieves all Guardian enrollments for a user.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/get_enrollments
func (m *UserManager) Enrollments(id string, opts ...RequestOption) (enrolls []*UserEnrollment, err error) {
err = m.Request("GET", m.URI("users", id, "enrollments"), &enrolls, opts...)
return
}
// RegenerateRecoveryCode removes the current multi-factor authentication recovery code and generate a new one.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/post_recovery_code_regeneration
func (m *UserManager) RegenerateRecoveryCode(id string, opts ...RequestOption) (*UserRecoveryCode, error) {
r := new(UserRecoveryCode)
err := m.Request("POST", m.URI("users", id, "recovery-code-regeneration"), &r, opts...)
return r, err
}
// InvalidateRememberBrowser invalidates all remembered browsers across all authentication factors for a user.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/post_invalidate_remember_browser
func (m *UserManager) InvalidateRememberBrowser(id string, opts ...RequestOption) error {
uri := m.URI(
"users",
id,
"multifactor",
"actions",
"invalidate-remember-browser",
)
err := m.Request("POST", uri, nil, opts...)
return err
}
// Link links two user accounts together forming a primary and secondary relationship.
//
// See: https://auth0.com/docs/api/management/v2#!/Users/post_identities
func (m *UserManager) Link(id string, il *UserIdentityLink, opts ...RequestOption) (uIDs []UserIdentity, err error) {
req, err := m.NewRequest("POST", m.URI("users", id, "identities"), il, opts...)
if err != nil {
return uIDs, err
}
res, err := m.Do(req)
if err != nil {
return uIDs, err
}
if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest {
return uIDs, newError(res.Body)
}
if res.StatusCode != http.StatusNoContent && res.StatusCode != http.StatusAccepted {
err := json.NewDecoder(res.Body).Decode(&uIDs)
if err != nil {
return uIDs, err
}
return uIDs, res.Body.Close()
}
return uIDs, nil
}
// List user's organizations
//
// See: https://auth0.com/docs/api/management/v2#!/Users/get_organizations
func (m *UserManager) Organizations(id string, opts ...RequestOption) (p *OrganizationList, err error) {
err = m.Request("GET", m.URI("users", id, "organizations"), &p, applyListDefaults(opts))
return
}