End users
An end user is a person who signs into your product through Huudis — not a member of your Huudis workspace. They appear in your Huudis admin surface because their OIDC client belongs to your workspace. The Go SDK exposes the ops namespace as client.EndUsers. For the data model see Concepts → End user; for the HTTP surface see API → End users.
Workspace members (people who can administer Huudis itself) are a different surface — see Users.
Field on the Client
client.EndUsers — type *huudis.EndUsersResource. Every method requires the caller to hold the huudis:ops:end-users:* scope — typically granted via the canned OpsSupport policy attached to your support team's group.
Methods
List
Signature. func (r *EndUsersResource) List(ctx context.Context, p ListEndUsersParams, auth RequestAuth) (*ListPage[EndUser], error)
Cursor-paginated. Search matches email or name (case-insensitive prefix). Default page size 25, max 100.
page, err := client.EndUsers.List(ctx, huudis.ListEndUsersParams{
Search: "alice",
Limit: 50,
}, huudis.RequestAuth{})
if err != nil {
return err
}
for _, u := range page.Items {
state := "active"
if u.Disabled {
state = "disabled"
}
last := u.LastLoginAt
if last == "" {
last = "never"
}
fmt.Println(u.Email, state, last)
}
Get
Signature. func (r *EndUsersResource) Get(ctx context.Context, id string, auth RequestAuth) (*EndUser, error)
Fetches one end user by ID.
u, err := client.EndUsers.Get(ctx, "eu_01HX...", huudis.RequestAuth{})
Revoke
Signature. func (r *EndUsersResource) Revoke(ctx context.Context, id string, auth RequestAuth) error
Revokes every active session for this end user. Refresh tokens are killed; existing access tokens are blocklisted (propagated via JWKS rotation within one minute). The user's record stays; their next attempt to use the product forces a re-login.
if err := client.EndUsers.Revoke(ctx, "eu_01HX...", huudis.RequestAuth{}); err != nil {
return err
}
Use after credential compromise or password reset.
SendPasswordReset
Signature. func (r *EndUsersResource) SendPasswordReset(ctx context.Context, id string, auth RequestAuth) error
Emails the user a tokenised reset link valid for one hour. Idempotent — repeated calls within the TTL re-use the same token.
_ = client.EndUsers.SendPasswordReset(ctx, "eu_01HX...", huudis.RequestAuth{})
VerifyEmail
Signature. func (r *EndUsersResource) VerifyEmail(ctx context.Context, id string, auth RequestAuth) error
Force-marks the user's email as verified, bypassing the confirm-by-email round-trip. Reserved for support flows where the user has proven ownership out-of-band.
_ = client.EndUsers.VerifyEmail(ctx, "eu_01HX...", huudis.RequestAuth{})
Impersonate
Signature. func (r *EndUsersResource) Impersonate(ctx context.Context, id string, in *ImpersonateInput, auth RequestAuth) (*ImpersonationSession, error)
Mints an access token that authenticates as the end user — used for "log in as this customer" support flows. The returned token's claims include act (the actor who impersonated) and actReason; every action taken under it is audit-logged with both identities.
session, err := client.EndUsers.Impersonate(ctx, "eu_01HX...", &huudis.ImpersonateInput{
Reason: "ticket #1234 — user reports broken billing page",
}, huudis.RequestAuth{})
if err != nil {
return err
}
log.Println(session.SessionID, session.ExpiresAt)
// Use session.AccessToken to call your product as the user.
Impersonation is logged. Every impersonation session emits
huudis.ops.impersonation_started.v1andhuudis.ops.impersonation_ended.v1audit events with the actor's identity, the target, the reason, and a session ID linking the two. Don't hide the reason field — it shows up on the customer-facing "an admin viewed your account" surface.
StopImpersonation
Signature. func (r *EndUsersResource) StopImpersonation(ctx context.Context, auth RequestAuth) error
Terminates the impersonation session on the calling actor's identity. Idempotent; safe to call when no session is active.
_ = client.EndUsers.StopImpersonation(ctx, huudis.RequestAuth{})
Disable / Enable
func (r *EndUsersResource) Disable(ctx context.Context, id string, in *DisableEndUserInput, auth RequestAuth) error
func (r *EndUsersResource) Enable(ctx context.Context, id string, auth RequestAuth) error
Disable sets disabled=true, blocks future sign-ins, revokes active sessions. Pair with a reason for the audit log. Enable reverses it (doesn't restore sessions; the user signs in fresh).
_ = client.EndUsers.Disable(ctx, "eu_01HX...", &huudis.DisableEndUserInput{
Reason: "fraud_review",
}, huudis.RequestAuth{})
// Later:
_ = client.EndUsers.Enable(ctx, "eu_01HX...", huudis.RequestAuth{})
Types
type EndUser struct {
ID string `json:"id"` // "eu_..."
AccountID string `json:"accountId"`
Email string `json:"email"`
Name string `json:"name,omitempty"`
EmailVerified bool `json:"emailVerified"`
Disabled bool `json:"disabled"`
CreatedAt string `json:"createdAt"` // ISO-8601
LastLoginAt string `json:"lastLoginAt,omitempty"`
}
type ImpersonationSession struct {
SessionID string `json:"sessionId"`
AccessToken string `json:"accessToken"`
ExpiresAt string `json:"expiresAt"`
}
See API → End users for field-level rules.
Common patterns
Support search
func findEndUser(ctx context.Context, c *huudis.Client, query string) ([]huudis.EndUser, error) {
page, err := c.EndUsers.List(ctx, huudis.ListEndUsersParams{
Search: query, Limit: 10,
}, huudis.RequestAuth{})
if err != nil {
return nil, err
}
return page.Items, nil
}
Scoped impersonation
Wrap in defer so an early return doesn't leave the session open:
func actAs(ctx context.Context, c *huudis.Client, userID, reason string, fn func(token string) error) error {
session, err := c.EndUsers.Impersonate(ctx, userID, &huudis.ImpersonateInput{Reason: reason}, huudis.RequestAuth{})
if err != nil {
return err
}
defer func() { _ = c.EndUsers.StopImpersonation(context.Background(), huudis.RequestAuth{}) }()
return fn(session.AccessToken)
}
Walk every end user
func allEndUsers(ctx context.Context, c *huudis.Client) ([]huudis.EndUser, error) {
var out []huudis.EndUser
var cursor string
for {
page, err := c.EndUsers.List(ctx, huudis.ListEndUsersParams{Limit: 100, Cursor: cursor}, huudis.RequestAuth{})
if err != nil {
return out, err
}
out = append(out, page.Items...)
if page.NextCursor == "" {
return out, nil
}
cursor = page.NextCursor
}
}
Errors
Code |
Status |
Cause |
|---|---|---|
not_found |
404 | End-user ID doesn't exist or lives in another workspace. |
state_conflict |
409 | Disabling an already-disabled user; impersonating while another impersonation is active. |
forbidden |
403 | Caller lacks huudis:ops:end-users:* scope. |
rate_limited |
429 | SendPasswordReset capped at 5/hour per user. |
Next
- Users — workspace members, not end users.
- API → End users — HTTP-level reference.