summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-07-29 19:30:24 -0400
committerDax Raad <[email protected]>2025-07-29 19:30:51 -0400
commit9bedd62da4fe76936c6755dd1138e07fd26b835a (patch)
treeb99ba3c90bacdd6ae6ce57033b7751b86feda912
parent4c34b69ae64bf0a04f532d88ea9296ccb2790475 (diff)
downloadopencode-9bedd62da4fe76936c6755dd1138e07fd26b835a.tar.gz
opencode-9bedd62da4fe76936c6755dd1138e07fd26b835a.zip
experimental well-known auth support
-rw-r--r--packages/opencode/src/auth/index.ts8
-rw-r--r--packages/opencode/src/cli/cmd/auth.ts41
-rw-r--r--packages/opencode/src/config/config.ts13
3 files changed, 53 insertions, 9 deletions
diff --git a/packages/opencode/src/auth/index.ts b/packages/opencode/src/auth/index.ts
index 76afa0383..ace51b26f 100644
--- a/packages/opencode/src/auth/index.ts
+++ b/packages/opencode/src/auth/index.ts
@@ -16,7 +16,13 @@ export namespace Auth {
key: z.string(),
})
- export const Info = z.discriminatedUnion("type", [Oauth, Api])
+ export const WellKnown = z.object({
+ type: z.literal("wellknown"),
+ key: z.string(),
+ token: z.string(),
+ })
+
+ export const Info = z.discriminatedUnion("type", [Oauth, Api, WellKnown])
export type Info = z.infer<typeof Info>
const filepath = path.join(Global.Path.data, "auth.json")
diff --git a/packages/opencode/src/cli/cmd/auth.ts b/packages/opencode/src/cli/cmd/auth.ts
index 854a8c06b..a9201a883 100644
--- a/packages/opencode/src/cli/cmd/auth.ts
+++ b/packages/opencode/src/cli/cmd/auth.ts
@@ -16,7 +16,7 @@ export const AuthCommand = cmd({
describe: "manage credentials",
builder: (yargs) =>
yargs.command(AuthLoginCommand).command(AuthLogoutCommand).command(AuthListCommand).demandCommand(),
- async handler() { },
+ async handler() {},
})
export const AuthListCommand = cmd({
@@ -61,20 +61,45 @@ export const AuthListCommand = cmd({
prompts.log.info(`${provider} ${UI.Style.TEXT_DIM}${envVar}`)
}
- prompts.outro(
- `${activeEnvVars.length} environment variable`
- + (activeEnvVars.length === 1 ? "" : "s")
- )
+ prompts.outro(`${activeEnvVars.length} environment variable` + (activeEnvVars.length === 1 ? "" : "s"))
}
},
})
export const AuthLoginCommand = cmd({
- command: "login",
+ command: "login [url]",
describe: "log in to a provider",
- async handler() {
- UI.empty()
+ builder: (yargs) =>
+ yargs.positional("url", {
+ describe: "opencode auth provider",
+ type: "string",
+ }),
+ async handler(args) {
prompts.intro("Add credential")
+ if (args.url) {
+ const wellknown = await fetch(`${args.url}/.well-known/opencode`).then((x) => x.json())
+ prompts.log.info(`Running \`${wellknown.auth.command.join(" ")}\``)
+ const proc = Bun.spawn({
+ cmd: wellknown.auth.command,
+ stdout: "pipe",
+ })
+ const exit = await proc.exited
+ if (exit !== 0) {
+ prompts.log.error("Failed")
+ prompts.outro("Done")
+ return
+ }
+ const token = await new Response(proc.stdout).text()
+ await Auth.set(args.url, {
+ type: "wellknown",
+ key: wellknown.auth.env,
+ token: token.trim(),
+ })
+ prompts.log.success("Logged into " + args.url)
+ prompts.outro("Done")
+ return
+ }
+ UI.empty()
const providers = await ModelsDev.get()
const priority: Record<string, number> = {
anthropic: 0,
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index 2d896a534..24903da56 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -11,11 +11,13 @@ import { lazy } from "../util/lazy"
import { NamedError } from "../util/error"
import matter from "gray-matter"
import { Flag } from "../flag/flag"
+import { Auth } from "../auth"
export namespace Config {
const log = Log.create({ service: "config" })
export const state = App.state("config", async (app) => {
+ const auth = await Auth.all()
let result = await global()
for (const file of ["opencode.jsonc", "opencode.json"]) {
const found = await Filesystem.findUp(file, app.path.cwd, app.path.root)
@@ -30,6 +32,14 @@ export namespace Config {
log.debug("loaded custom config", { path: Flag.OPENCODE_CONFIG })
}
+ for (const [key, value] of Object.entries(auth)) {
+ if (value.type === "wellknown") {
+ process.env[value.key] = value.token
+ const wellknown = await fetch(`${key}/.well-known/opencode`).then((x) => x.json())
+ result = mergeDeep(result, await loadRaw(JSON.stringify(wellknown.config ?? {}), process.cwd()))
+ }
+ }
+
result.agent = result.agent || {}
const markdownAgents = [
...(await Filesystem.globUp("agent/*.md", Global.Path.config, Global.Path.config)),
@@ -307,7 +317,10 @@ export namespace Config {
throw new JsonError({ path: configPath }, { cause: err })
})
if (!text) return {}
+ return loadRaw(text, configPath)
+ }
+ async function loadRaw(text: string, configPath: string) {
text = text.replace(/\{env:([^}]+)\}/g, (_, varName) => {
return process.env[varName] || ""
})