Hallo Stroke

Backend Authentication

JWT dual-token auth, middleware, NIK encryption, and password reset.

Dual-token JWT

Secrets from env: JWT_ACCESS_SECRET, JWT_REFRESH_SECRET.

TokenAlgorithmClaimsExpiryStorage
AccessHS256{user_id, exp, iat}60 minutesclient localStorage
RefreshHS256{user_id, exp, iat}60 daysusers.refresh_token column
Super-adminHS256{username, role:"superadmin", exp, iat}1 hourclient localStorage

Refresh validates both the signed token and that it matches the value stored on the user row — so a revoked/rotated refresh token is rejected even if the signature is valid.

Middleware (middleware/auth.go)

Loading diagram...

Handler identity extraction

Every handler that needs the caller identity repeats:

claims := c.Locals("user").(*jwt.Token).Claims.(jwt.MapClaims)
userID := uint(claims["user_id"].(float64))

Password hashing

utils/hash.go — bcrypt (GenerateFromPassword / CompareHashAndPassword).

NIK encryption (PII)

The 16-digit NIK (national ID) is AES-GCM encrypted before storage (utils/AESencrypt.go, key from AES_ENCRYPTION_KEY — 32 bytes):

  • Encrypted at registration and admin-create.
  • Decrypted on read in GetProfile, GetUserByID, GetAllAdmins.
  • There are (commented-out) admin endpoints EncryptAllNIK / EncryptNIKById to migrate legacy plaintext NIKs.

Password reset flow

Loading diagram...

Registration

POST /api/register accepts {username, email?, password, nik(16), nama_ktp, nama_samaran, nomor_hp, role?, preferences?}:

  • NIK encrypted with AES-GCM
  • Phone normalized to 62-prefix
  • Returns {access_token, refresh_token}

POST /api/auth/check-username checks availability before submission.

Required env vars

config.GetEnv(key) fatals on missing variables — the app refuses to start without all required secrets (JWT_ACCESS_SECRET, JWT_REFRESH_SECRET, AES_ENCRYPTION_KEY, etc.).

On this page