@@ -8,7 +8,7 @@ S05 brings the first real domain surface to shithub: email/password signup, emai |
| 8 | 8 | - argon2id password hashing with PHC string encoding. |
| 9 | 9 | - Strict username whitelist + reserved-name list. |
| 10 | 10 | - Common-password rejection from an embedded SecLists 10k corpus. |
| 11 | | -- Email Sender abstraction with stdout (dev), SMTP (MailHog/local), and Postmark (prod) backends. |
| 11 | +- Email Sender abstraction with stdout (dev), SMTP (MailHog/local), Postmark, and Resend backends. |
| 12 | 12 | - Counter-based rate-limiting backed by Postgres (no Redis dep). |
| 13 | 13 | - Auth handlers: signup, login, logout, password reset (request + confirm), email verification, verification resend. |
| 14 | 14 | - Constant-time login: missing usernames still trigger an argon2 hash against a pre-computed dummy. |
@@ -78,17 +78,18 @@ To refresh: replace `internal/passwords/common_passwords.txt` with a newer SecLi |
| 78 | 78 | |
| 79 | 79 | ## Email service |
| 80 | 80 | |
| 81 | | -`internal/auth/email` defines the `Sender` interface. Three implementations: |
| 81 | +`internal/auth/email` defines the `Sender` interface. Four implementations: |
| 82 | 82 | |
| 83 | 83 | - `StdoutSender` — writes a human-readable dump to a writer. Default in dev when no SMTP is configured. Convenient for tests. |
| 84 | 84 | - `SMTPSender` — plain SMTP for MailHog locally. Authenticated and TLS-upgrade variants supported. |
| 85 | | -- `PostmarkSender` — Postmark transactional API. Production default. |
| 85 | +- `PostmarkSender` — Postmark transactional API. |
| 86 | +- `ResendSender` — Resend transactional API (https://resend.com). Comparable feature set to Postmark; preferred where onboarding speed matters (no human approval queue). |
| 86 | 87 | |
| 87 | 88 | `messages.go` hosts the `VerifyMessage` and `ResetMessage` builders. Both produce HTML + plaintext bodies — every transactional email shithub sends works in plain-text-only clients. Templates are inlined (short, rarely change); when they grow, promote to `templates/email/*.{html,txt}`. |
| 88 | 89 | |
| 89 | 90 | ### Wiring |
| 90 | 91 | |
| 91 | | -`auth.email_backend` chooses the implementation: `stdout | smtp | postmark`. The `smtp` backend additionally requires `auth.smtp.addr`; `postmark` requires `auth.postmark.server_token`. Validation enforces these. |
| 92 | +`auth.email_backend` chooses the implementation: `stdout | smtp | postmark | resend`. The `smtp` backend additionally requires `auth.smtp.addr`; `postmark` requires `auth.postmark.server_token`; `resend` requires `auth.resend.api_key`. Validation enforces these. |
| 92 | 93 | |
| 93 | 94 | ```sh |
| 94 | 95 | # Dev: capture mail in MailHog |
@@ -179,11 +180,12 @@ All auth settings flow through `internal/infra/config` (see `docs/internal/confi |
| 179 | 180 | | `auth.base_url` | string | `http://127.0.0.1:8080` | Used for absolute links in emails. | |
| 180 | 181 | | `auth.site_name` | string | `shithub` | Branding token for email subjects/bodies. | |
| 181 | 182 | | `auth.email_from` | string | `shithub <noreply@shithub.local>` | Envelope From for outgoing email. | |
| 182 | | -| `auth.email_backend` | string | `stdout` | `stdout | smtp | postmark`. | |
| 183 | +| `auth.email_backend` | string | `stdout` | `stdout | smtp | postmark | resend`. | |
| 183 | 184 | | `auth.smtp.addr` | string | `127.0.0.1:1025` | Required when `email_backend=smtp`. | |
| 184 | 185 | | `auth.smtp.username` | string | `""` | Optional. | |
| 185 | 186 | | `auth.smtp.password` | string | `""` | Optional. Redacted by `config print`. | |
| 186 | 187 | | `auth.postmark.server_token` | string | `""` | Required when `email_backend=postmark`. Redacted. | |
| 188 | +| `auth.resend.api_key` | string | `""` | Required when `email_backend=resend`. Redacted. | |
| 187 | 189 | | `auth.argon2.memory_kib` | uint32 | `65536` | argon2id memory cost (KiB). | |
| 188 | 190 | | `auth.argon2.time` | uint32 | `3` | argon2id iterations. | |
| 189 | 191 | | `auth.argon2.threads` | uint8 | `2` | argon2id lanes. | |