Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/cloud-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ jobs:
alera-google-oauth-client-secret
alera-tombstone-pepper
)
# A web client id mounts its secret on the Cloud Run revision, so that
# secret must have a version before the image build starts.
for provider in google github; do
if grep -Eq "^web_${provider}_oauth_client_id[[:space:]]*=[[:space:]]*\"[^\"]+\"" \
infra/production/production.auto.tfvars; then
required_secrets+=("alera-web-${provider}-oauth-client-secret")
fi
done
for secret in "${required_secrets[@]}"; do
enabled_version="$(
gcloud secrets versions list "$secret" \
Expand Down
1 change: 1 addition & 0 deletions docs/cloud-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ gcloud secrets versions add alera-edge-origin-token --data-file=-
gcloud secrets versions add alera-github-oauth-client-secret --data-file=-
gcloud secrets versions add alera-google-oauth-client-secret --data-file=-
gcloud secrets versions add alera-tombstone-pepper --data-file=-
gcloud secrets versions add alera-web-google-oauth-client-secret --data-file=-
```

Generate independent high-entropy values for the edge token and tombstone pepper. Do not reuse an OAuth client secret or copy local development values.
Expand Down
16 changes: 14 additions & 2 deletions docs/cloud-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ Record:
- Client id: public configuration in `terraform.tfvars`
- Client secret: secret value added to `alera-google-oauth-client-secret`

MCP and device sign-in run in a browser and return to `https://api.alera.build/oauth/callback`, which a desktop client cannot accept. Create a second OAuth client for them:

- Application type: Web application
- Name: `Alera Web`
- Authorized redirect URI: `https://api.alera.build/oauth/callback`

Record its client id as `web_google_oauth_client_id` and add its secret to `alera-web-google-oauth-client-secret` before the id is applied.

The backend verifies the Google ID token, including signature, issuer, audience, authorized presenter, expiry, and nonce. Provider tokens are discarded after identity resolution.

## GitHub OAuth Registration
Expand All @@ -171,9 +179,10 @@ Configuration:
- Application name: `Alera`
- Homepage URL: `https://alera.build`
- Authorization callback URL: `http://127.0.0.1/callback`
- Second redirect URI: `https://api.alera.build/oauth/callback`
- Device Flow: disabled

The runtime supplies the actual loopback port. GitHub permits a loopback redirect to vary the port while preserving the registered host and path.
The runtime supplies the actual loopback port. GitHub permits a loopback redirect to vary the port while preserving the registered host and path. The second URI serves MCP and device sign-in, so production reuses this app for them and leaves `web_github_oauth_client_id` empty.

The application requests only:

Expand Down Expand Up @@ -293,7 +302,7 @@ The value is public signing-key material and may appear in OpenTofu state. The p

## Secret Manager Values

OpenTofu creates six secret containers. Five require initial values:
OpenTofu creates eight secret containers. Five require initial values, and a web OAuth secret is required once its client id is set:

| Secret | Value |
| --- | --- |
Expand All @@ -303,6 +312,8 @@ OpenTofu creates six secret containers. Five require initial values:
| `alera-google-oauth-client-secret` | Google desktop OAuth client secret |
| `alera-tombstone-pepper` | Independent random value with at least 32 characters |
| `alera-edge-previous-origin-token` | Leave without a version until an edge-token rotation |
| `alera-web-google-oauth-client-secret` | Google web OAuth client secret, required while `web_google_oauth_client_id` is set |
| `alera-web-github-oauth-client-secret` | Leave without a version while `web_github_oauth_client_id` is empty |

Add values through standard input:

Expand All @@ -312,6 +323,7 @@ gcloud secrets versions add alera-edge-origin-token --data-file=-
gcloud secrets versions add alera-github-oauth-client-secret --data-file=-
gcloud secrets versions add alera-google-oauth-client-secret --data-file=-
gcloud secrets versions add alera-tombstone-pepper --data-file=-
gcloud secrets versions add alera-web-google-oauth-client-secret --data-file=-
```

Use a password manager or secure random generator for the origin token and tombstone pepper. They must be unrelated values and must not reuse either OAuth secret.
Expand Down
2 changes: 1 addition & 1 deletion docs/remote-mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Rules:
- OAuth endpoints use the standard snake_case field names and `{ error, error_description }` errors; every other route keeps camelCase and `{ error: { code, message } }`.
- Unknown scopes such as `offline_access` are ignored, and `mcp:read` is always granted. A token request may omit `redirect_uri`; when present it must match.
- `ALERA_MCP_ENABLED=false` removes the metadata, registration, authorize, token, revoke, and gateway routes. Device sign-in, grant listing, and runtime naming keep working.
- The web login uses `{ALERA_PUBLIC_BASE_URL}/oauth/callback`. Production needs web OAuth clients for Google and GitHub that admit that redirect: `ALERA_WEB_GOOGLE_CLIENT_ID`, `ALERA_WEB_GOOGLE_CLIENT_SECRET`, `ALERA_WEB_GITHUB_CLIENT_ID`, and `ALERA_WEB_GITHUB_CLIENT_SECRET`. Without them the native client credentials are reused.
- The web login uses `{ALERA_PUBLIC_BASE_URL}/oauth/callback`. Each provider needs a client that admits that redirect. Google desktop clients only accept loopback redirects, so production sets a separate Google web client (`ALERA_WEB_GOOGLE_CLIENT_ID` from `web_google_oauth_client_id`, `ALERA_WEB_GOOGLE_CLIENT_SECRET` from the `alera-web-google-oauth-client-secret` secret). A GitHub OAuth App accepts several redirect URIs, so production reuses the desktop app with that callback added and leaves `ALERA_WEB_GITHUB_CLIENT_ID` and `ALERA_WEB_GITHUB_CLIENT_SECRET` unset. Without web credentials a provider reuses the native client.

### Device Authorization

Expand Down
23 changes: 12 additions & 11 deletions infra/production/production.auto.tfvars
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
gcp_project_id = "alera-production"
gcp_region = "us-central1"
cloudflare_zone_id = "d5bb590bba0a461c5a5f699b40b2c95f"
api_hostname = "api.alera.build"
google_oauth_client_id = "850463913236-eun5inavt29h0cpanc3utkvpdu4tari5.apps.googleusercontent.com"
github_oauth_client_id = "Ov23lihNhXgxBYUsBk3N"
neon_project_id = "empty-glade-74978232"
signing_key_id = "alera-production-v1"
kms_key_version = "1"
kms_public_key_b64url = "4OHKJMPgzVh_4XSvY11WVLqTSNPG_opDR53rPMp-3y4"
previous_jwks_json = "{\"keys\":[]}"
gcp_project_id = "alera-production"
gcp_region = "us-central1"
cloudflare_zone_id = "d5bb590bba0a461c5a5f699b40b2c95f"
api_hostname = "api.alera.build"
google_oauth_client_id = "850463913236-eun5inavt29h0cpanc3utkvpdu4tari5.apps.googleusercontent.com"
github_oauth_client_id = "Ov23lihNhXgxBYUsBk3N"
web_google_oauth_client_id = "850463913236-s6laqmn715qj97rjjjp863epsn87325d.apps.googleusercontent.com"
Comment thread
leynier marked this conversation as resolved.
neon_project_id = "empty-glade-74978232"
signing_key_id = "alera-production-v1"
kms_key_version = "1"
kms_public_key_b64url = "4OHKJMPgzVh_4XSvY11WVLqTSNPG_opDR53rPMp-3y4"
previous_jwks_json = "{\"keys\":[]}"
1 change: 1 addition & 0 deletions infra/production/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ gcloud secrets versions add alera-edge-origin-token --data-file=-
gcloud secrets versions add alera-github-oauth-client-secret --data-file=-
gcloud secrets versions add alera-google-oauth-client-secret --data-file=-
gcloud secrets versions add alera-tombstone-pepper --data-file=-
gcloud secrets versions add alera-web-google-oauth-client-secret --data-file=-
```

Use independent random values for the origin token and tombstone pepper. Never reuse an OAuth client secret.
Expand Down
Loading