use super::{write_file, Scaffold, ScaffoldArgs, ScaffoldResult};
use anyhow::Result;
pub struct SocialAuthScaffold;
impl Scaffold for SocialAuthScaffold {
fn name(&self) -> &'static str {
"social-auth"
}
fn description(&self) -> &'static str {
"OAuth login: GitHub/Google/Discord/Twitter, account linking, state verification"
}
fn generate(&self, args: &ScaffoldArgs) -> Result<ScaffoldResult> {
let mut r = ScaffoldResult::default();
let d = args.dry_run;
write_file(
&mut r,
"src/app/controllers/oauth_controller.rs",
CONTROLLER,
d,
)?;
write_file(
&mut r,
"migrations/create_social_accounts_table.sql",
MIGRATION,
d,
)?;
r.warnings
.push("Set GITHUB_CLIENT_ID/SECRET, GOOGLE_CLIENT_ID/SECRET in .env".into());
r.warnings.push(
"Register GET /auth/{provider}/redirect and /auth/{provider}/callback routes".into(),
);
Ok(r)
}
}
const CONTROLLER: &str = r#"use axum::{extract::{Path, Query, State}, response::{IntoResponse, Redirect}};
use rok_auth::axum::Response;
use serde::Deserialize;
#[derive(Deserialize)]
pub struct OAuthCallback {
pub code: String,
pub state: Option<String>,
}
pub async fn redirect(Path(provider): Path<String>) -> impl IntoResponse {
// TODO: generate state param, build provider auth URL, redirect
match provider.as_str() {
"github" | "google" | "discord" | "twitter" => {
Redirect::to("https://provider-auth-url.example.com/authorize").into_response()
}
_ => Response::bad_request("Unknown provider").into_response(),
}
}
pub async fn callback(
Path(provider): Path<String>,
Query(q): Query<OAuthCallback>,
State(pool): State<sqlx::PgPool>,
) -> impl IntoResponse {
// TODO: verify state, exchange code for token, fetch profile, upsert social_account, issue JWT
Response::json(serde_json::json!({ "message": "OAuth not fully implemented" }))
}
"#;
const MIGRATION: &str = r#"CREATE TABLE social_accounts (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
provider TEXT NOT NULL,
provider_id TEXT NOT NULL,
access_token TEXT,
refresh_token TEXT,
profile JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (provider, provider_id)
);
"#;