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
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ API_PORT=3003
CLIENT_ID=dev-rp-CHANGE-FOR-PRODUCTION
CLIENT_SECRET=dev-secret-CHANGE-FOR-PRODUCTION
REDIRECT_URI=https://app.localtest.me/callback
POST_LOGOUT_REDIRECT_URI=https://app.localtest.me

# ===== APPLICATION SECRETS =====
# For development: Use this placeholder value
Expand Down
68 changes: 68 additions & 0 deletions .github/workflows/deploy-heroku.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Deploy all services to Heroku via container registry
# Triggers on every push to main, or manually via workflow_dispatch
name: Deploy to Heroku

on:
push:
branches: [main]
workflow_dispatch:

env:
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}

jobs:
build-and-push:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- service: auth
dockerfile: apps/auth/Dockerfile
app: plaidypus-auth
- service: api
dockerfile: apps/api/Dockerfile
app: plaidypus-api
- service: app
dockerfile: apps/app/Dockerfile
app: plaidypus-app
steps:
- uses: actions/checkout@v4

- name: Login to Heroku Container Registry
run: echo "$HEROKU_API_KEY" | docker login --username=_ --password-stdin registry.heroku.com

- name: Build Docker image
run: docker build -f ${{ matrix.dockerfile }} -t registry.heroku.com/${{ matrix.app }}/web .

- name: Push Docker image
run: docker push registry.heroku.com/${{ matrix.app }}/web

release-auth:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Install Heroku CLI
run: curl https://cli-assets.heroku.com/install.sh | sh

- name: Release auth
run: heroku container:release web --app plaidypus-auth

release-api:
needs: release-auth
runs-on: ubuntu-latest
steps:
- name: Install Heroku CLI
run: curl https://cli-assets.heroku.com/install.sh | sh

- name: Release API
run: heroku container:release web --app plaidypus-api

release-app:
needs: release-api
runs-on: ubuntu-latest
steps:
- name: Install Heroku CLI
run: curl https://cli-assets.heroku.com/install.sh | sh

- name: Release app
run: heroku container:release web --app plaidypus-app
2 changes: 1 addition & 1 deletion apps/api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3003/health || exit 1

# Start the application
CMD ["node", "apps/api/dist/index.js"]
CMD ["sh", "-c", "API_PORT=${PORT:-${API_PORT}} node apps/api/dist/index.js"]
2 changes: 1 addition & 1 deletion apps/app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,4 @@ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3004/ || exit 1

# Start the application
CMD ["node", "apps/app/dist/index.js"]
CMD ["sh", "-c", "APP_PORT=${PORT:-${APP_PORT}} node apps/app/dist/index.js"]
1 change: 1 addition & 0 deletions apps/auth/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ OP_PORT=3001
CLIENT_ID=dev-rp-CHANGE-FOR-PRODUCTION
CLIENT_SECRET=dev-secret-CHANGE-FOR-PRODUCTION
REDIRECT_URI=https://app.localtest.me/callback
POST_LOGOUT_REDIRECT_URI=https://app.localtest.me

# ===== API CONFIGURATION =====
API_AUDIENCE=api://my-api
Expand Down
2 changes: 1 addition & 1 deletion apps/auth/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,4 @@ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/.well-known/openid-configuration || exit 1

# Start the application
CMD ["node", "apps/auth/dist/index.js"]
CMD ["sh", "-c", "OP_PORT=${PORT:-${OP_PORT}} node apps/auth/dist/index.js"]
2 changes: 1 addition & 1 deletion apps/auth/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function loadOIDCClients() {
client_id: getRequiredEnv( "CLIENT_ID", "dev-rp" ),
client_secret: getRequiredEnv( "CLIENT_SECRET", "dev-secret" ),
redirect_uris: [ getRequiredEnv( "REDIRECT_URI", "https://app.localtest.me/callback" ) ],
post_logout_redirect_uris: [ "https://app.localtest.me" ],
post_logout_redirect_uris: [ getRequiredEnv( "POST_LOGOUT_REDIRECT_URI", "https://app.localtest.me" ) ],
grant_types: [ "authorization_code", "refresh_token" ],
response_types: [ "code" ],
token_endpoint_auth_method: "client_secret_basic"
Expand Down
149 changes: 149 additions & 0 deletions docs/heroku-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Heroku Deployment Setup

Prerequisites for deploying the three services (`plaidypus-auth`, `plaidypus-api`, `plaidypus-app`) via the GitHub Actions workflow.

## 1. Create Heroku Apps

```bash
# If you're using a personal account, use these commands
heroku create plaidypus-auth --stack container
heroku create plaidypus-api --stack container
heroku create plaidypus-app --stack container

# If you're using a team account, add the --team argument
heroku create plaidypus-auth --stack container --team <your-team-name>
heroku create plaidypus-api --stack container --team <your-team-name>
heroku create plaidypus-app --stack container --team <your-team-name>
```

These commands will generate unique URLs for the services, such as `https://plaidypus-auth-xxxxx.herokuapp.com` where the `xxxxx` is a unique key.

If the apps already exist but aren't on the container stack:

```bash
heroku stack:set container --app plaidypus-auth
heroku stack:set container --app plaidypus-api
heroku stack:set container --app plaidypus-app
```

## 2. Generate Production Secrets

```bash
node scripts/secrets.js all
```

Save the output — you'll use the generated values in the next step.

## 3. Set Config Vars

`CLIENT_ID` and `CLIENT_SECRET` must match between plaidypus-auth and plaidypus-app.

### plaidypus-auth

```bash
heroku config:set --app plaidypus-auth \
OP_ISSUER=https://plaidypus-auth-xxxxx.herokuapp.com \
API_AUDIENCE=api://my-api \
CLIENT_ID=<generated> \
CLIENT_SECRET=<generated> \
REDIRECT_URI=https://plaidypus-app-xxxxx.herokuapp.com/callback \
POST_LOGOUT_REDIRECT_URI=https://plaidypus-app-xxxxx.herokuapp.com \
JWKS='<generated>' \
LOG_LEVEL=info
```

### plaidypus-api

```bash
heroku config:set --app plaidypus-api \
OP_ISSUER=https://plaidypus-auth-xxxxx.herokuapp.com \
API_AUDIENCE=api://my-api \
LOG_LEVEL=info
```

### plaidypus-app

```bash
heroku config:set --app plaidypus-app \
OP_ISSUER=https://plaidypus-auth-xxxxx.herokuapp.com \
APP_HOST=https://plaidypus-app-xxxxx.herokuapp.com \
APP_BASE_URL=https://plaidypus-app-xxxxx.herokuapp.com \
API_BASE_URL=https://plaidypus-api-xxxxx.herokuapp.com \
REDIRECT_URI=https://plaidypus-app-xxxxx.herokuapp.com/callback \
API_AUDIENCE=api://my-api \
CLIENT_ID=<generated, must match plaidypus-auth> \
CLIENT_SECRET=<generated, must match plaidypus-auth> \
COOKIE_SECRET=<generated> \
LOG_LEVEL=info
```

## 4. Get Your Heroku API Key

```bash
# Short-lived token (1 month)
heroku auth:token

# Long-lived token (1 year)
heroku authorizations:create

# Token: <your-heroku-api-token>
```

## 5. Add GitHub Repository Secret

```bash
gh secret set HEROKU_API_KEY --repo plaid/core-exchange-node-example
```

Paste the token from step 4 when prompted.

## 6. Deploy

### Manual deploy (before workflow is on main)

Run from the repo root:

```bash
heroku container:login

# Auth
docker buildx build --platform linux/amd64 --provenance=false -f apps/auth/Dockerfile -t registry.heroku.com/plaidypus-auth/web --load .
docker push registry.heroku.com/plaidypus-auth/web
heroku container:release web --app plaidypus-auth

# API
docker buildx build --platform linux/amd64 --provenance=false -f apps/api/Dockerfile -t registry.heroku.com/plaidypus-api/web --load .
docker push registry.heroku.com/plaidypus-api/web
heroku container:release web --app plaidypus-api

# App
docker buildx build --platform linux/amd64 --provenance=false -f apps/app/Dockerfile -t registry.heroku.com/plaidypus-app/web --load .
docker push registry.heroku.com/plaidypus-app/web
heroku container:release web --app plaidypus-app
```

### GitHub Actions (after workflow is merged to main)

Deploys automatically on every push to `main`. Can also be triggered manually:

```bash
gh workflow run "Deploy to Heroku"
```

Or use the "Run workflow" button on the Actions tab in GitHub.

## 7. Verify

```bash
# Check logs
heroku logs --tail --app plaidypus-auth
heroku logs --tail --app plaidypus-api
heroku logs --tail --app plaidypus-app

# Verify endpoints
curl https://plaidypus-auth-xxxxx.herokuapp.com/.well-known/openid-configuration
curl https://plaidypus-api-xxxxx.herokuapp.com/public/health
curl -I https://plaidypus-app-xxxxx.herokuapp.com
```

Test the full OIDC flow by visiting `https://plaidypus-app-xxxxx.herokuapp.com` and logging in with the demo credentials (`user@example.test` / `passw0rd!`).