diff --git a/.env.example b/.env.example index c125ca5..e2b16e2 100644 --- a/.env.example +++ b/.env.example @@ -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 diff --git a/.github/workflows/deploy-heroku.yml b/.github/workflows/deploy-heroku.yml new file mode 100644 index 0000000..4da6458 --- /dev/null +++ b/.github/workflows/deploy-heroku.yml @@ -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 diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index 9120de1..f263a42 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -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"] diff --git a/apps/app/Dockerfile b/apps/app/Dockerfile index b76f3c9..fe9c1af 100644 --- a/apps/app/Dockerfile +++ b/apps/app/Dockerfile @@ -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"] diff --git a/apps/auth/.env.example b/apps/auth/.env.example index 809c148..f19374d 100644 --- a/apps/auth/.env.example +++ b/apps/auth/.env.example @@ -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 diff --git a/apps/auth/Dockerfile b/apps/auth/Dockerfile index c03a4b6..51866a6 100644 --- a/apps/auth/Dockerfile +++ b/apps/auth/Dockerfile @@ -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"] diff --git a/apps/auth/src/index.ts b/apps/auth/src/index.ts index 3f0399a..57b0ec1 100644 --- a/apps/auth/src/index.ts +++ b/apps/auth/src/index.ts @@ -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" diff --git a/docs/heroku-setup.md b/docs/heroku-setup.md new file mode 100644 index 0000000..54b9ccf --- /dev/null +++ b/docs/heroku-setup.md @@ -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 +heroku create plaidypus-api --stack container --team +heroku create plaidypus-app --stack container --team +``` + +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= \ + CLIENT_SECRET= \ + REDIRECT_URI=https://plaidypus-app-xxxxx.herokuapp.com/callback \ + POST_LOGOUT_REDIRECT_URI=https://plaidypus-app-xxxxx.herokuapp.com \ + JWKS='' \ + 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= \ + CLIENT_SECRET= \ + COOKIE_SECRET= \ + 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: +``` + +## 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!`).