Skip to main content

Core Module

The Core Module is the foundation of every GoAuth installation. It is auto-registered by auth.New() — you never register it manually via Use(). It owns the full user lifecycle: registration, profile management, password flows, email/phone verification, and availability checks. It does not handle login/logout/refresh — those are managed by the Session or Stateless auth module. Every other module depends on Core for user storage and authentication middleware.

Capabilities

  • User Registration — Email/password signup with optional username, phone, and name fields. Configurable field requirements (require username, require phone, enforce unique phone).
  • Profile Management — View (/me) and update user info (name, phone, avatar). Profile data is always scoped to the authenticated user.
  • Password Reset — Full token-based forgot/reset flow. Emits events for the Notification module to deliver reset emails automatically.
  • Password Change — Authenticated change with old password verification. Emits events so audit and notification modules can react.
  • Email Verification — Send, resend, and verify via secure token. Supports frontend redirect on verification. Integrates with Notification module for delivery.
  • Phone Verification — Send, resend, and verify via OTP code. Requires the Notification module with an SMS sender configured for delivery.
  • Availability Check — Single endpoint to check email, username, or phone availability before registration.
  • Account Lockout — Built-in tracking of failed login attempts with configurable lockout threshold and duration (default: 5 attempts, 15-minute lockout).
  • Password Policy Enforcement — Configurable minimum/maximum length (default: 8/128 characters).
  • Event-Driven Architecture — Emits before/after events for every major action, enabling other modules and custom handlers to react to user lifecycle changes.

Configuration

Core configuration is set via Config.Core on the top-level config. Since Core is auto-registered, there is no Use() call for it.

a, _ := auth.New(&config.Config{
Storage: store,
BasePath: "/api/v1",

Core: &config.CoreConfig{
RequireEmailVerification: true,
RequirePhoneVerification: false,
RequireUserName: false,
RequirePhoneNumber: false,
UniquePhoneNumber: true,
},

Security: types.SecurityConfig{
JwtSecretKey: "your-secret-key-min-32-chars!!!!",
EncryptionKey: "your-encryption-key-32-chars!",
Session: types.SessionConfig{
AccessTokenTTL: 15 * time.Minute,
RefreshTokenTTL: 7 * 24 * time.Hour,
},
},

FrontendConfig: &config.FrontendConfig{
URL: "http://localhost:3000",
Domain: "localhost",
VerifyEmailCallbackPath: "/verify-email",
ResetPasswordPath: "/reset-password",
},
})

CoreConfig Fields

FieldTypeDefaultDescription
RequireEmailVerificationboolfalseIf true, sends verification email automatically after signup
RequirePhoneVerificationboolfalseIf true, sends verification SMS automatically after signup
RequireUserNameboolfalseIf true, username is required during signup
RequirePhoneNumberboolfalseIf true, phone number is required during signup
UniquePhoneNumberboolfalseIf true, enforces unique phone numbers

Endpoints

All paths are prefixed with your BasePath (default: /auth).

Registration

POST /signup

{
"email": "user@example.com",
"password": "SecurePassword123!",
"name": "John Doe",
"first_name": "John",
"last_name": "Doe",
"username": "johndoe",
"phone_number": "+1234567890"
}

Profile

MethodPathAuthDescription
GET/meYesGet current user info
PUT/profileYesUpdate profile (name, phone, avatar)

Password

MethodPathAuthDescription
PUT/change-passwordYesChange password (requires old password)
POST/forgot-passwordNoRequest password reset email
POST/reset-passwordNoReset password with token

Verification

MethodPathAuthDescription
POST/send-verification-emailNoSend email verification link
POST/resend-verification-emailNoResend email verification link
GET/verify-email?token=...&email=...NoVerify email (redirects to frontend)
POST/send-verification-phoneNoSend phone verification OTP
POST/resend-verification-phoneNoResend phone verification OTP
POST/verify-phoneNoVerify phone with OTP code

Availability

POST /is-available

Check whether an email, username, or phone is available. Send exactly one field:

{ "email": "user@example.com" }
{ "username": "johndoe" }
{ "phone": "+1234567890" }

Response:

{
"data": {
"available": true,
"field": "email",
"message": "email is available"
}
}

Events

The Core Module emits events you can subscribe to:

a.On(types.EventAfterSignup, func(ctx context.Context, e *types.Event) error {
log.Printf("New user: %+v", e.Data)
return nil
})

Hook Events (emitted by Core)

CategoryBeforeAfter
SignupEventBeforeSignupEventAfterSignup
Password ChangeEventBeforeChangePasswordEventAfterChangePassword
Profile UpdateEventBeforeChangeProfileEventAfterChangeProfile
Forgot PasswordEventBeforeForgotPasswordEventAfterForgotPassword
Reset PasswordEventBeforeResetPasswordEventAfterResetPassword
Email VerifiedEventAfterEmailVerified

Action Events (trigger delivery via Notification module)

EventDescription
EventSendEmailVerificationRequests email verification delivery
EventSendPhoneVerificationRequests phone verification delivery
EventSendPasswordResetEmailRequests password reset email delivery

Login/Logout Events (emitted by Session or Stateless module)

These are not emitted by Core, but by whichever auth module you register:

BeforeAfter
EventBeforeLoginEventAfterLogin
EventBeforeLogoutEventAfterLogout

Additional auth events: EventAfterPasswordVerified, EventAuthLoginSuccess, EventAuthLoginFailed.

Data Models

User

type User struct {
ID string `json:"id"`
Name string `json:"name"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Username string `json:"username"`
Avatar string `json:"avatar"`
PhoneNumber string `json:"phone_number"`
Active bool `json:"active"`
EmailVerified bool `json:"email_verified"`
PhoneNumberVerified bool `json:"phone_number_verified"`
IsSuperAdmin bool `json:"is_super_admin"`
TokenVersion int `json:"-"`
FailedLoginAttempts int `json:"-"`
LockedUntil *time.Time `json:"-"`
CreatedAt time.Time `json:"created_at"`
LastLoginAt *time.Time `json:"last_login_at"`
UpdatedAt *time.Time `json:"updated_at"`
}

Fields hidden from JSON (tagged json:"-"):

  • PasswordHash — bcrypt hash, never exposed
  • TokenVersion — incremented to invalidate all existing tokens for stateless revocation
  • FailedLoginAttempts — tracks failed logins for account lockout
  • LockedUntil — account lockout expiry timestamp

Storage

The Core module uses the shared storage layer configured in Config.Storage. Since Core is auto-registered, you do not pass custom storage to it directly. Instead, configure the top-level Storage when creating the auth instance:

store, _ := storage.NewGormStorage(storage.GormConfig{
Dialect: types.DialectTypePostgres,
DSN: "host=localhost user=postgres ...",
})

a, _ := auth.New(&config.Config{
Storage: store,
// ...
})

Core accesses Storage.Core() which provides:

  • UserRepository — CRUD operations on the users table
  • TokenRepository — Manages verification tokens and refresh nonces
  • VerificationTokenRepository — Manages email/phone verification tokens

To use a custom storage backend, implement the types.Storage interface and pass it as Config.Storage. All modules, including Core, will use your implementation.

Next Steps