Deploying ACUL Screens via GitHub Actions to AWS S3
November 24, 2025 · View on GitHub
This guide walks you through setting up automated deployment for your Auth0 Universal Login screens using GitHub Actions.
Want to understand the workflow? See .github/GITHUB_ACTIONS.md for details on how the deployment pipeline works.
What You'll Need
- Auth0 tenant with admin access
- AWS account (for hosting assets)
- GitHub repository with your login screen code
Setup Overview
The deployment system automatically builds your screens, uploads them to AWS S3, and configures Auth0 to use them. Here's what you need to set up:
- Auth0 configuration (custom domain + API access)
- AWS infrastructure (S3 bucket + IAM role)
- GitHub secrets (to connect everything)
1. Auth0 Setup
Set Up a Custom Domain
Custom login screens require a custom domain.
- Go to Auth0 Dashboard → Branding → Custom Domains
- Click Add Domain
- Follow the verification steps
- Make sure the domain shows as "Verified" before continuing
Create API Access
The workflow needs API access to configure your screens automatically.
- Go to Applications → Applications
- Click Create Application
- Choose Machine to Machine Applications
- Name it "GitHub Actions Deployment" (or whatever makes sense to you)
- Select Auth0 Management API
- Grant these permissions:
read:brandingupdate:brandingread:promptsupdate:promptsread:custom_domains
- Save the Domain, Client ID, and Client Secret - you'll need these for GitHub
2. AWS Setup
Create an S3 Bucket
This is where your built screens will be stored.
- Go to AWS Console → S3
- Click Create bucket
- Pick a unique name (e.g.,
my-company-login-screens) - Choose your region
- Enable versioning (recommended)
- Leave the rest as default for now
Choose Your Access Strategy
You have two options for serving files from S3:
Option A: Public S3 Bucket (Simpler)
Make the bucket publicly readable:
- In your bucket, go to Permissions → Bucket Policy
- Add this policy (replace
YOUR-BUCKET-NAME):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
}
]
}
Option B: CloudFront + Private S3 (Recommended)
Keep the bucket private and use CloudFront as a gateway. This approach requires a combined bucket policy that allows both CloudFront to read files and GitHub Actions to upload them.
- Go to CloudFront → Create Distribution
- Select your S3 bucket as the origin
- Choose Origin access control (recommended)
- Under Viewer Protocol, select "Redirect HTTP to HTTPS"
- Set Cache Policy to "CachingOptimized"
- Create the distribution
- Copy the CloudFront domain (e.g.,
d1234abcdef.cloudfront.net)
After creating your CloudFront distribution and IAM role for GitHub Actions, update your S3 bucket policy to allow both services:
- Go to your S3 bucket → Permissions → Bucket Policy
- Add this combined policy (replace with your actual values):
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::YOUR-ACCOUNT-ID:distribution/YOUR-DISTRIBUTION-ID"
}
}
},
{
"Sid": "AllowGitHubActionsRoleToModify",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::YOUR-ACCOUNT-ID:role/YOUR-GITHUB-ACTIONS-ROLE"
},
"Action": [
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::YOUR-BUCKET-NAME",
"arn:aws:s3:::YOUR-BUCKET-NAME/*"
]
}
]
}
What this policy does:
- First statement: Lets CloudFront read files to serve them publicly
- Second statement: Lets GitHub Actions upload/delete files during deployment
CloudFront gives you HTTPS, better performance, and keeps your S3 bucket private. Use this if security matters.
Create IAM Role for GitHub
GitHub Actions needs permission to upload files to your bucket.
- Go to IAM → Roles → Create role
- Select Web identity
- Choose
token.actions.githubusercontent.comas the identity provider - Set audience to
sts.amazonaws.com - For organization/repo, enter your GitHub org name and repo
Trust Policy (allows GitHub Actions to assume this role):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::YOUR-ACCOUNT-ID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:YOUR-ORG/YOUR-REPO:ref:refs/heads/main"
}
}
}
]
}
Permissions Policy (what the role can do with S3):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
},
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME"
}
]
}
- Name the role (e.g., "GitHubActions-LoginScreens")
- Copy the role ARN - you'll need it for GitHub
3. GitHub Configuration
Add Repository Secrets
Go to Settings → Secrets and variables → Actions in your GitHub repo and add these secrets:
| Secret | Value | Notes |
|---|---|---|
AWS_S3_ARN | arn:aws:iam::123456789012:role/... | The IAM role ARN from AWS |
S3_BUCKET_NAME | my-company-login-screens | Your S3 bucket name |
AWS_REGION | us-east-1 | Where your bucket lives |
S3_CDN_URL | https://d1234abcdef.cloudfront.net | CloudFront domain OR S3 public URL (no trailing slash) |
AUTH0_DOMAIN | dev-mycompany.auth0.com | Your Auth0 domain |
AUTH0_CLIENT_ID | abc123... | M2M app client ID |
AUTH0_CLIENT_SECRET | xyz789... | M2M app secret |
That's It
The workflow file is already in .github/workflows/acul-deploy.yml. It will run automatically when you push to main.
Using the Deployment
Automatic Deployment
Just push to the main branch. The workflow will:
- Build your screens
- Upload them to S3
- Configure Auth0 to use them
Watch the progress in the Actions tab.
Manual Deployment
- Go to Actions tab
- Select the deployment workflow
- Click Run workflow
- Choose your branch and run it
Controlling What Gets Deployed
Edit .github/config/deploy_config.yml:
default_screen_deployment_status:
"login-id": true # This will deploy
"login-password": false # This won't deploy
Set everything to false and the workflow will skip building entirely.
Troubleshooting
Auth0 errors?
- Double-check your
AUTH0_DOMAIN,AUTH0_CLIENT_ID, andAUTH0_CLIENT_SECRET - Make sure the M2M app has all the required permissions
- Verify your custom domain is active
S3 upload fails?
- Check the
AWS_S3_ARNis correct - Verify the IAM role trusts
token.actions.githubusercontent.com - Make sure the role has S3 write permissions
Screens don't load in Auth0?
- Check browser console for 404 errors
- Verify
S3_CDN_URLis correct - If using CloudFront, make sure it can access your S3 bucket
- Confirm your custom domain is set up in Auth0
Assets not loading?
- Check if your S3 bucket policy allows public access (if not using CloudFront)
- If using CloudFront, verify the distribution is deployed (not just "In Progress")
- Look at the deployment logs to see what URLs were configured
How Assets Work
Each file gets a unique hash in its filename based on its content:
login-id.abc123.jsinstead of justlogin-id.js- When you change the file, the hash changes
- Old versions stay cached, new versions get fresh URLs
- No need to manually clear CDN caches
This means fast loading for users and no stale content issues.