Support Claude Code Max via OAuth token
Publish Image / publish (push) Successful in 21s Details

Pass CLAUDE_CODE_OAUTH_TOKEN to workspaces so they use the Max
subscription instead of pay-per-use API credits. Falls back to
ANTHROPIC_API_KEY if OAuth token not set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Daniel Samson 2026-04-12 14:52:01 +01:00
parent 9bca465565
commit abbe47b1b9
No known key found for this signature in database
GPG Key ID: A9EB2589C60F7268
3 changed files with 24 additions and 3 deletions

View File

@ -196,6 +196,15 @@ data "coder_parameter" "callback_url" {
mutable = false mutable = false
} }
data "coder_parameter" "claude_oauth_token" {
name = "claude_oauth_token"
display_name = "Claude OAuth Token"
description = "OAuth token for Claude Code Max subscription"
type = "string"
default = ""
mutable = false
}
data "coder_parameter" "deploy_env" { data "coder_parameter" "deploy_env" {
name = "deploy_env" name = "deploy_env"
display_name = "Deploy Environment" display_name = "Deploy Environment"
@ -414,7 +423,8 @@ resource "coder_agent" "main" {
} }
env = { env = {
ANTHROPIC_API_KEY = data.coder_parameter.anthropic_api_key.value ANTHROPIC_API_KEY = data.coder_parameter.anthropic_api_key.value
CLAUDE_CODE_OAUTH_TOKEN = data.coder_parameter.claude_oauth_token.value
GITHUB_TOKEN = data.coder_external_auth.github.access_token GITHUB_TOKEN = data.coder_external_auth.github.access_token
GITEA_TOKEN = data.coder_parameter.gitea_token.value GITEA_TOKEN = data.coder_parameter.gitea_token.value
GITEA_ORG = data.coder_parameter.gitea_org.value GITEA_ORG = data.coder_parameter.gitea_org.value
@ -576,6 +586,11 @@ resource "kubernetes_deployment_v1" "workspace" {
value = data.coder_parameter.anthropic_api_key.value value = data.coder_parameter.anthropic_api_key.value
} }
env {
name = "CLAUDE_CODE_OAUTH_TOKEN"
value = data.coder_parameter.claude_oauth_token.value
}
env { env {
name = "GITHUB_TOKEN" name = "GITHUB_TOKEN"
value = data.coder_external_auth.github.access_token value = data.coder_external_auth.github.access_token

View File

@ -11,8 +11,10 @@ export interface Config {
giteaDevToken: string; giteaDevToken: string;
/** Gitea API token for the review bot account */ /** Gitea API token for the review bot account */
giteaReviewToken: string; giteaReviewToken: string;
/** Anthropic API key passed to Claude Code in workspaces */ /** Anthropic API key passed to Claude Code in workspaces (fallback) */
anthropicApiKey: string; anthropicApiKey: string;
/** Claude Code OAuth token for Max subscription (preferred) */
claudeOauthToken: string;
/** Username of the dev bot (to filter out self-replies) */ /** Username of the dev bot (to filter out self-replies) */
botDevUsername: string; botDevUsername: string;
/** Username of the review bot (to filter out self-replies) */ /** Username of the review bot (to filter out self-replies) */
@ -41,7 +43,8 @@ export function loadConfig(): Config {
coderTemplateId: required("CODER_TEMPLATE_ID"), coderTemplateId: required("CODER_TEMPLATE_ID"),
giteaDevToken: required("GITEA_DEV_TOKEN"), giteaDevToken: required("GITEA_DEV_TOKEN"),
giteaReviewToken: required("GITEA_REVIEW_TOKEN"), giteaReviewToken: required("GITEA_REVIEW_TOKEN"),
anthropicApiKey: required("ANTHROPIC_API_KEY"), anthropicApiKey: process.env.ANTHROPIC_API_KEY || "",
claudeOauthToken: process.env.CLAUDE_OAUTH_TOKEN || "",
botDevUsername: process.env.BOT_DEV_USERNAME || "claude-dev", botDevUsername: process.env.BOT_DEV_USERNAME || "claude-dev",
botReviewUsername: process.env.BOT_REVIEW_USERNAME || "claude-review", botReviewUsername: process.env.BOT_REVIEW_USERNAME || "claude-review",
giteaUrl: process.env.GITEA_URL || "https://gitea.samson.media", giteaUrl: process.env.GITEA_URL || "https://gitea.samson.media",

View File

@ -7,6 +7,7 @@ export class CoderClient {
private token: string; private token: string;
private templateId: string; private templateId: string;
private anthropicApiKey: string; private anthropicApiKey: string;
private claudeOauthToken: string;
private callbackUrl: string; private callbackUrl: string;
constructor(config: Config) { constructor(config: Config) {
@ -14,6 +15,7 @@ export class CoderClient {
this.token = config.coderToken; this.token = config.coderToken;
this.templateId = config.coderTemplateId; this.templateId = config.coderTemplateId;
this.anthropicApiKey = config.anthropicApiKey; this.anthropicApiKey = config.anthropicApiKey;
this.claudeOauthToken = config.claudeOauthToken;
this.callbackUrl = config.callbackUrl; this.callbackUrl = config.callbackUrl;
} }
@ -31,6 +33,7 @@ export class CoderClient {
{ name: "gitea_org", value: task.giteaOrg }, { name: "gitea_org", value: task.giteaOrg },
{ name: "gitea_repo", value: task.giteaRepo }, { name: "gitea_repo", value: task.giteaRepo },
{ name: "anthropic_api_key", value: this.anthropicApiKey }, { name: "anthropic_api_key", value: this.anthropicApiKey },
{ name: "claude_oauth_token", value: this.claudeOauthToken },
{ name: "callback_url", value: `${this.callbackUrl}/webhook/task-complete/${name}` }, { name: "callback_url", value: `${this.callbackUrl}/webhook/task-complete/${name}` },
...(task.deployEnv ...(task.deployEnv
? [{ name: "deploy_env", value: task.deployEnv }] ? [{ name: "deploy_env", value: task.deployEnv }]