wip gateway
Some checks are pending
deploy / deploy (push) Waiting to run

This commit is contained in:
Frank 2025-08-09 01:28:27 -04:00
parent 81a3e02474
commit 7446f5ad7b
7 changed files with 75 additions and 89 deletions

View file

@ -2,7 +2,9 @@ import { Resource } from "sst"
import { z } from "zod" import { z } from "zod"
import { issuer } from "@openauthjs/openauth" import { issuer } from "@openauthjs/openauth"
import { createSubjects } from "@openauthjs/openauth/subject" import { createSubjects } from "@openauthjs/openauth/subject"
import { CodeProvider } from "@openauthjs/openauth/provider/code"
import { GithubProvider } from "@openauthjs/openauth/provider/github" import { GithubProvider } from "@openauthjs/openauth/provider/github"
import { GoogleOidcProvider } from "@openauthjs/openauth/provider/google"
import { CloudflareStorage } from "@openauthjs/openauth/storage/cloudflare" import { CloudflareStorage } from "@openauthjs/openauth/storage/cloudflare"
import { Account } from "@opencode/cloud-core/account.js" import { Account } from "@opencode/cloud-core/account.js"
@ -30,6 +32,53 @@ export default {
clientSecret: Resource.GITHUB_CLIENT_SECRET_CONSOLE.value, clientSecret: Resource.GITHUB_CLIENT_SECRET_CONSOLE.value,
scopes: ["read:user", "user:email"], scopes: ["read:user", "user:email"],
}), }),
google: GoogleOidcProvider({
clientID: Resource.GOOGLE_CLIENT_ID.value,
scopes: ["openid", "email"],
}),
// email: CodeProvider({
// async request(req, state, form, error) {
// console.log(state)
// const params = new URLSearchParams()
// if (error) {
// params.set("error", error.type)
// }
// if (state.type === "start") {
// return Response.redirect(process.env.AUTH_FRONTEND_URL + "/auth/email?" + params.toString(), 302)
// }
//
// if (state.type === "code") {
// return Response.redirect(process.env.AUTH_FRONTEND_URL + "/auth/code?" + params.toString(), 302)
// }
//
// return new Response("ok")
// },
// async sendCode(claims, code) {
// const email = z.string().email().parse(claims.email)
// const cmd = new SendEmailCommand({
// Destination: {
// ToAddresses: [email],
// },
// FromEmailAddress: `SST <auth@${Resource.Email.sender}>`,
// Content: {
// Simple: {
// Body: {
// Html: {
// Data: `Your pin code is <strong>${code}</strong>`,
// },
// Text: {
// Data: `Your pin code is ${code}`,
// },
// },
// Subject: {
// Data: "SST Console Pin Code: " + code,
// },
// },
// },
// })
// await ses.send(cmd)
// },
// }),
}, },
storage: CloudflareStorage({ storage: CloudflareStorage({
namespace: env.AuthStorage, namespace: env.AuthStorage,
@ -50,7 +99,14 @@ export default {
}) })
const user = (await userResponse.json()) as { email: string } const user = (await userResponse.json()) as { email: string }
email = user.email email = user.email
} else throw new Error("Unsupported provider") } else if (response.provider === "google") {
if (!response.id.email_verified) throw new Error("Google email not verified")
email = response.id.email as string
}
//if (response.provider === "email") {
// email = response.claims.email
//}
else throw new Error("Unsupported provider")
if (!email) throw new Error("No email found") if (!email) throw new Error("No email found")

View file

@ -50,6 +50,10 @@ declare module "sst" {
"type": "sst.sst.Secret" "type": "sst.sst.Secret"
"value": string "value": string
} }
"GOOGLE_CLIENT_ID": {
"type": "sst.sst.Secret"
"value": string
}
"OPENAI_API_KEY": { "OPENAI_API_KEY": {
"type": "sst.sst.Secret" "type": "sst.sst.Secret"
"value": string "value": string

View file

@ -24,9 +24,12 @@ export default function Index() {
</section> </section>
<section data-slot="cta"> <section data-slot="cta">
<div data-slot="col-2"> <div>
<span onClick={() => auth.authorize({ provider: "github" })}>Sign in with GitHub</span> <span onClick={() => auth.authorize({ provider: "github" })}>Sign in with GitHub</span>
</div> </div>
<div>
<span onClick={() => auth.authorize({ provider: "google" })}>Sign in with Google</span>
</div>
</section> </section>
</div> </div>
</div> </div>

View file

@ -80,90 +80,4 @@
border-left: 2px solid var(--color-border); border-left: 2px solid var(--color-border);
} }
} }
[data-slot="images"] {
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: space-between;
border-top: 2px solid var(--color-border);
& > div {
flex: 1;
display: flex;
flex-direction: column;
gap: calc(var(--padding) / 4);
padding: calc(var(--padding) / 2);
border-width: 0;
border-style: solid;
border-color: var(--color-border);
& > div, a {
flex: 1;
display: flex;
align-items: center;
}
}
p {
letter-spacing: -0.03125rem;
text-transform: uppercase;
color: var(--color-text-dimmed);
}
& > div + div {
border-width: 0 0 0 2px;
}
@media (max-width: 30rem) {
& {
flex-direction: column;
}
& > div + div {
border-width: 2px 0 0 0;
}
}
}
[data-slot="content"] {
border-top: 2px solid var(--color-border);
padding: var(--padding);
& > p {
line-height: var(--font-line-height);
}
ol {
margin-top: calc(var(--vertical-padding) / 2);
padding-left: 2.5rem;
list-style-type: decimal;
line-height: var(--font-line-height);
& > li + li {
margin-top: calc(var(--vertical-padding) / 2);
}
& > li b {
text-transform: uppercase;
}
}
}
[data-slot="footer"] {
border-top: 2px solid var(--color-border);
display: flex;
flex-direction: row;
& > div {
flex: 1;
text-align: center;
text-transform: uppercase;
padding: calc(var(--padding) / 2) 0.5rem;
}
& > div + div {
border-left: 2px solid var(--color-border);
}
}
} }

View file

@ -56,12 +56,13 @@ new sst.x.DevCommand("Studio", {
const GITHUB_CLIENT_ID_CONSOLE = new sst.Secret("GITHUB_CLIENT_ID_CONSOLE") const GITHUB_CLIENT_ID_CONSOLE = new sst.Secret("GITHUB_CLIENT_ID_CONSOLE")
const GITHUB_CLIENT_SECRET_CONSOLE = new sst.Secret("GITHUB_CLIENT_SECRET_CONSOLE") const GITHUB_CLIENT_SECRET_CONSOLE = new sst.Secret("GITHUB_CLIENT_SECRET_CONSOLE")
const GOOGLE_CLIENT_ID = new sst.Secret("GOOGLE_CLIENT_ID")
const authStorage = new sst.cloudflare.Kv("AuthStorage") const authStorage = new sst.cloudflare.Kv("AuthStorage")
export const auth = new sst.cloudflare.Worker("AuthApi", { export const auth = new sst.cloudflare.Worker("AuthApi", {
domain: `auth.${domain}`, domain: `auth.${domain}`,
handler: "cloud/function/src/auth.ts", handler: "cloud/function/src/auth.ts",
url: true, url: true,
link: [database, authStorage, GITHUB_CLIENT_ID_CONSOLE, GITHUB_CLIENT_SECRET_CONSOLE], link: [database, authStorage, GITHUB_CLIENT_ID_CONSOLE, GITHUB_CLIENT_SECRET_CONSOLE, GOOGLE_CLIENT_ID],
}) })
const ANTHROPIC_API_KEY = new sst.Secret("ANTHROPIC_API_KEY") const ANTHROPIC_API_KEY = new sst.Secret("ANTHROPIC_API_KEY")

View file

@ -50,6 +50,10 @@ declare module "sst" {
"type": "sst.sst.Secret" "type": "sst.sst.Secret"
"value": string "value": string
} }
"GOOGLE_CLIENT_ID": {
"type": "sst.sst.Secret"
"value": string
}
"OPENAI_API_KEY": { "OPENAI_API_KEY": {
"type": "sst.sst.Secret" "type": "sst.sst.Secret"
"value": string "value": string

4
sst-env.d.ts vendored
View file

@ -63,6 +63,10 @@ declare module "sst" {
"type": "sst.sst.Secret" "type": "sst.sst.Secret"
"value": string "value": string
} }
"GOOGLE_CLIENT_ID": {
"type": "sst.sst.Secret"
"value": string
}
"GatewayApi": { "GatewayApi": {
"type": "sst.cloudflare.Worker" "type": "sst.cloudflare.Worker"
"url": string "url": string