SES Auth Email
Current Recommendation
Retired for authentication. Clerk sends its own verification and password
email, so SES is no longer part of sign-in — see
auth-sessions.md.
The stack below is kept because the domain identity and DKIM records are reusable, and because nothing should delete production DNS on the strength of one migration. Do not wire it back into an auth flow. Check whether any other feature has adopted SES before removing the infrastructure.
The Terraform stack at infra/terraform/ses provisions the SES domain identity, DKIM, custom MAIL FROM records, and an optional least-privilege IAM access key for Convex.
Current hosted baseline:
- domain identity:
vrdex.net - sender:
no-reply@vrdex.net - region:
us-east-1 - Route 53 hosted zone:
vrdex.nethosted zone; provider-generated hosted zone IDs stay in provider configuration, Terraform state, or operator records rather than public docs - Terraform state key:
ses/terraform.tfstate
As of the AWS baseline pass, SES identity verification and DKIM verification are both Success, and Terraform reports no drift for the hosted SES stack.
Convex Environment Variables
Set these in each Convex deployment that sends email:
AWS_SES_REGIONAWS_SES_FROM_EMAILAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYVRDEX_APP_NAMEoptional display name for email copy
Adapter Environment Variables
Discord community Administrator verification:
DISCORD_BOT_TOKEN: Discord bot token for reading guild, member, and role stateDISCORD_API_BASE_URL: optional override, defaults tohttps://discord.com/api/v10
The bot must be present in claimed guilds and able to read members and roles.
VRChat and VRCLinking proof-code verification:
VRCHAT_PROOF_ADAPTER_URL: POST endpoint for VRChat user/group proof checksVRCLINKING_PROOF_ADAPTER_URL: POST endpoint for VRCLinking proof checksVRCHAT_PROOF_ADAPTER_BEARER_TOKEN: required whenever either adapter URL is set, and must match the value the adapter itself requires. Convex refuses to call an adapter without it rather than sending an unauthenticated request that the adapter would answer with a 401 — which the claim path reads as the non-terminalunavailable, so the claim would stall with the misconfiguration reported nowhere.VRCLINKING_ADAPTER_CAPABILITY_KEY: required wheneverVRCLINKING_PROOF_ADAPTER_URLis set. Signs the per-delegation capability the adapter verifies asVRDEX_VRCLINKING_CAPABILITY_KEY. Keep it a different value from the bearer token: the bearer token authenticates the channel, and this authorizes the individual guild, so a leak of the first must not confer the second.
Adapter URLs must use https, or http only on loopback for a local stub.
Every request carries the bearer token.
The two adapters receive different payloads, and an implementation written against the wrong one waits for fields it never gets:
VRCHAT_PROOF_ADAPTER_URLreceivestargetType(vrchat_userorvrchat_group),targetExternalId,proofCode, and safe profile context. It answers whether the code is present on that target.VRCLINKING_PROOF_ADAPTER_URLreceivestargetType: "vrclinking",targetExternalId,discordUserId, and adelegationsarray of{ guildId, secretRef, expiresAt, capability }. It receives no proof code and no profile context — it answers from a delegated key, so neither is of any use to it. Seedocs/backend/vrclinking-api.mdfor the delegation contract and what a positive result must carry back.
Both return JSON with verified, evidenceSource, and evidenceSummary.
Sandbox Note
SES domain verification and DKIM do not automatically move an AWS account out of SES sandbox mode. Request SES production access in AWS before relying on real user emails outside verified recipient addresses.
The hosted AWS account currently has a production-shaped SES quota. Keep this documented status current if the SES region, sender domain, or account changes.
Relationship To AWS Baseline
The broader AWS baseline, including private S3 profile assets tracked by #115, lives in docs/deployment/aws-baseline.md.