tenseleyflow/shithub / f27fcda

Browse files

docs: document the resend email backend

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
f27fcdad4d9e62424a708f8cc00ad0e8830b2cd3
Parents
5302fc9
Tree
9f70a28

3 changed files

StatusFile+-
M .env.example 3 1
M docs/internal/auth.md 7 5
M docs/internal/config.md 2 1
.env.examplemodified
@@ -37,12 +37,14 @@ SHITHUB_AUTH__REQUIRE_EMAIL_VERIFICATION=false
3737
 SHITHUB_AUTH__BASE_URL=http://127.0.0.1:8080
3838
 SHITHUB_AUTH__SITE_NAME=shithub
3939
 SHITHUB_AUTH__EMAIL_FROM=shithub <noreply@shithub.local>
40
-# stdout (default in dev), smtp (MailHog), or postmark.
40
+# stdout (default in dev), smtp (MailHog), postmark, or resend.
4141
 SHITHUB_AUTH__EMAIL_BACKEND=stdout
4242
 # When email_backend=smtp:
4343
 SHITHUB_AUTH__SMTP__ADDR=127.0.0.1:1025
4444
 # When email_backend=postmark:
4545
 # SHITHUB_AUTH__POSTMARK__SERVER_TOKEN=...
46
+# When email_backend=resend (https://resend.com — no approval queue):
47
+# SHITHUB_AUTH__RESEND__API_KEY=re_...
4648
 
4749
 # AEAD key for at-rest TOTP secrets (S06). Generate once and persist —
4850
 # rotating without re-encrypting every row breaks every existing 2FA login.
docs/internal/auth.mdmodified
@@ -8,7 +8,7 @@ S05 brings the first real domain surface to shithub: email/password signup, emai
88
 - argon2id password hashing with PHC string encoding.
99
 - Strict username whitelist + reserved-name list.
1010
 - 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.
1212
 - Counter-based rate-limiting backed by Postgres (no Redis dep).
1313
 - Auth handlers: signup, login, logout, password reset (request + confirm), email verification, verification resend.
1414
 - 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
7878
 
7979
 ## Email service
8080
 
81
-`internal/auth/email` defines the `Sender` interface. Three implementations:
81
+`internal/auth/email` defines the `Sender` interface. Four implementations:
8282
 
8383
 - `StdoutSender` — writes a human-readable dump to a writer. Default in dev when no SMTP is configured. Convenient for tests.
8484
 - `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).
8687
 
8788
 `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}`.
8889
 
8990
 ### Wiring
9091
 
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.
9293
 
9394
 ```sh
9495
 # Dev: capture mail in MailHog
@@ -179,11 +180,12 @@ All auth settings flow through `internal/infra/config` (see `docs/internal/confi
179180
 | `auth.base_url` | string | `http://127.0.0.1:8080` | Used for absolute links in emails. |
180181
 | `auth.site_name` | string | `shithub` | Branding token for email subjects/bodies. |
181182
 | `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`. |
183184
 | `auth.smtp.addr` | string | `127.0.0.1:1025` | Required when `email_backend=smtp`. |
184185
 | `auth.smtp.username` | string | `""` | Optional. |
185186
 | `auth.smtp.password` | string | `""` | Optional. Redacted by `config print`. |
186187
 | `auth.postmark.server_token` | string | `""` | Required when `email_backend=postmark`. Redacted. |
188
+| `auth.resend.api_key` | string | `""` | Required when `email_backend=resend`. Redacted. |
187189
 | `auth.argon2.memory_kib` | uint32 | `65536` | argon2id memory cost (KiB). |
188190
 | `auth.argon2.time` | uint32 | `3` | argon2id iterations. |
189191
 | `auth.argon2.threads` | uint8 | `2` | argon2id lanes. |
docs/internal/config.mdmodified
@@ -59,11 +59,12 @@ shithubd version # includes a one-line summary of which sinks are confi
5959
 | `auth.base_url` | string | `http://127.0.0.1:8080` | Used for absolute links in transactional emails. |
6060
 | `auth.site_name` | string | `shithub` | Branding token for email subjects/bodies. |
6161
 | `auth.email_from` | string | `shithub <noreply@shithub.local>` | Envelope From for outgoing email. |
62
-| `auth.email_backend` | string | `stdout` | One of `stdout | smtp | postmark`. |
62
+| `auth.email_backend` | string | `stdout` | One of `stdout | smtp | postmark | resend`. |
6363
 | `auth.smtp.addr` | string | `127.0.0.1:1025` | Required when `email_backend=smtp`. |
6464
 | `auth.smtp.username` | string | `""` | Optional SMTP auth username. |
6565
 | `auth.smtp.password` | string | `""` | Optional SMTP auth password. Redacted by `config print`. |
6666
 | `auth.postmark.server_token` | string | `""` | Required when `email_backend=postmark`. Redacted. |
67
+| `auth.resend.api_key` | string | `""` | Required when `email_backend=resend`. Redacted. |
6768
 | `auth.argon2.memory_kib` | uint32 | `65536` | argon2id memory cost (KiB). |
6869
 | `auth.argon2.time` | uint32 | `3` | argon2id iterations. |
6970
 | `auth.argon2.threads` | uint8 | `2` | argon2id parallelism. |