Add GitHub OAuth login with provider registry
Implement OAuth 2.0 login via GitHub as an alternative to email/password. Uses a provider registry pattern (internal/auth/oauth/) so adding Google or other providers later requires only a new Provider implementation. Flow: GET /v1/auth/oauth/github redirects to GitHub, callback exchanges the code for a user profile, upserts the user + team atomically, and redirects to the frontend with a JWT token. Key changes: - Migration: make password_hash nullable, add oauth_providers table - Provider registry with GitHubProvider (profile + email fallback) - CSRF state cookie with HMAC-SHA256 validation - Race-safe registration (23505 collision retries as login) - Startup validation: CP_PUBLIC_URL required when OAuth is configured Not fully tested — needs integration tests with a real GitHub OAuth app and end-to-end testing with the frontend callback page.
This commit is contained in:
22
db/migrations/20260315001514_oauth.sql
Normal file
22
db/migrations/20260315001514_oauth.sql
Normal file
@ -0,0 +1,22 @@
|
||||
-- +goose Up
|
||||
|
||||
ALTER TABLE users
|
||||
ALTER COLUMN password_hash DROP NOT NULL;
|
||||
|
||||
CREATE TABLE oauth_providers (
|
||||
provider TEXT NOT NULL,
|
||||
provider_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
email TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
PRIMARY KEY (provider, provider_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_oauth_providers_user ON oauth_providers(user_id);
|
||||
|
||||
-- +goose Down
|
||||
|
||||
DROP TABLE oauth_providers;
|
||||
|
||||
UPDATE users SET password_hash = '' WHERE password_hash IS NULL;
|
||||
ALTER TABLE users ALTER COLUMN password_hash SET NOT NULL;
|
||||
7
db/queries/oauth.sql
Normal file
7
db/queries/oauth.sql
Normal file
@ -0,0 +1,7 @@
|
||||
-- name: InsertOAuthProvider :exec
|
||||
INSERT INTO oauth_providers (provider, provider_id, user_id, email)
|
||||
VALUES ($1, $2, $3, $4);
|
||||
|
||||
-- name: GetOAuthProvider :one
|
||||
SELECT * FROM oauth_providers
|
||||
WHERE provider = $1 AND provider_id = $2;
|
||||
@ -8,3 +8,8 @@ SELECT * FROM users WHERE email = $1;
|
||||
|
||||
-- name: GetUserByID :one
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
|
||||
-- name: InsertUserOAuth :one
|
||||
INSERT INTO users (id, email)
|
||||
VALUES ($1, $2)
|
||||
RETURNING *;
|
||||
|
||||
Reference in New Issue
Block a user