| name | setup-mocksaml |
|---|---|
| description | Set up MockSAML as a local SAML IdP for testing SSO flows (grant migration, invite enforcement). Run when setting up a fresh local env or after `supabase db reset`. |
| disable-model-invocation | true |
This skill configures the local Supabase environment to support SAML SSO login via mocksaml.com, enabling end-to-end testing of SSO grant migration (phase 4a) and invite link SSO enforcement (phase 4b).
- Local Supabase must be running (
supabase startorsupabase db reset) - Docker must be accessible (may require
limactl shell <vm>prefix if Supabase runs in a Lima VM — check the memory file for this project)
Execute these steps in order. Stop and report if any step fails.
Try docker ps directly. If that fails with a Docker daemon error, try
limactl shell tiger docker ps. Use whichever works as the docker command
prefix for all subsequent steps. If neither works, stop and tell the user
to start Docker or their Lima VM.
<docker-prefix> docker ps --filter name=supabase_auth_flow --format '{{.Status}}'If not running, tell the user to run supabase start first.
<docker-prefix> docker exec supabase_auth_flow env | grep GOTRUE_SAML_ENABLEDIf GOTRUE_SAML_ENABLED=true is already set, skip to step 6.
openssl genrsa 2048 > /tmp/saml_key.pemGoTrue requires PKCS#1 format. Check the header of the generated key:
head -1 /tmp/saml_key.pemBEGIN RSA PRIVATE KEY→ PKCS#1, good to go.BEGIN PRIVATE KEY→ PKCS#8 (OpenSSL 3.x default). Convert it:openssl rsa -traditional -in /tmp/saml_key.pem -out /tmp/saml_key.pem
Strip to raw base64 (no PEM headers, no newlines):
SAML_KEY_B64=$(grep -v "^-----" /tmp/saml_key.pem | tr -d '\n')Capture the current container's env vars, image, and network:
<docker-prefix> docker inspect supabase_auth_flow --format '{{range .Config.Env}}{{println .}}{{end}}' > /tmp/auth_env.txt
<docker-prefix> docker inspect supabase_auth_flow --format '{{.Config.Image}}'
# Network is typically supabase_network_flow — confirm via:
<docker-prefix> docker inspect supabase_auth_flow --format '{{json .NetworkSettings.Networks}}'Build an env file for the new container. Using --env-file avoids shell
parsing issues with values that contain template syntax (e.g.
GOTRUE_SMS_TEMPLATE=Your code is {{ .Code }}).
grep -v -E '^(PATH=|API_EXTERNAL_URL=)' /tmp/auth_env.txt > /tmp/auth_env_filtered.txt
echo "GOTRUE_SAML_ENABLED=true" >> /tmp/auth_env_filtered.txt
echo "GOTRUE_SAML_PRIVATE_KEY=$SAML_KEY_B64" >> /tmp/auth_env_filtered.txt
echo "API_EXTERNAL_URL=http://127.0.0.1:5431/auth/v1" >> /tmp/auth_env_filtered.txtImportant: the API_EXTERNAL_URL override includes the /auth/v1 prefix —
GoTrue uses this to generate the SAML ACS callback URL, and without the prefix
Kong won't route the callback correctly.
If using Lima, copy the env file into the VM before running docker:
limactl copy /tmp/auth_env_filtered.txt <vm>:/tmp/auth_env_filtered.txtStop and remove the old container, then recreate:
<docker-prefix> docker stop supabase_auth_flow && <docker-prefix> docker rm supabase_auth_flow
<docker-prefix> docker run -d \
--name supabase_auth_flow \
--network <network-name> \
--restart always \
--env-file /tmp/auth_env_filtered.txt \
<image> authVerify it started successfully (look for "GoTrue API started on"):
sleep 3 && <docker-prefix> docker logs supabase_auth_flow --tail 5If it's crash-looping, check the logs for the error and report to the user.
supabase status --output jsonExtract SERVICE_ROLE_KEY from the output.
If supabase status fails (e.g. Docker runs inside a Lima VM), read the key
from Kong's config instead — it's always accessible since Kong handles routing:
<docker-prefix> docker exec supabase_kong_flow cat /home/kong/kong.ymlLook for the service_role JWT in the authorization header rewriting rules.
psql postgresql://postgres:postgres@localhost:5432/postgres \
-c "SELECT id FROM auth.sso_providers LIMIT 1;"If a provider already exists, confirm with the user whether to reuse it or register a new one. If reusing, skip to step 9.
Ask the user which email domain to associate with the SSO provider (default:
example.com). This controls which email addresses are routed through SAML
login. MockSAML's default test user is jackson@example.com, so example.com
works out of the box — but the user may want a different domain to match their
test data.
curl -X POST 'http://127.0.0.1:5431/auth/v1/admin/sso/providers' \
-H 'Authorization: Bearer <SERVICE_ROLE_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"type": "saml",
"metadata_url": "https://mocksaml.com/api/saml/metadata",
"domains": ["<DOMAIN>"]
}'Save the id from the response.
Ask the user which tenant to configure. Then:
UPDATE tenants
SET sso_provider_id = '<PROVIDER_UUID>'
WHERE tenant = '<tenant>/';Verify:
SELECT tenant, sso_provider_id FROM tenants WHERE sso_provider_id IS NOT NULL;Initiate an SSO login to verify everything works:
curl -s -X POST 'http://127.0.0.1:5431/auth/v1/sso' \
-H 'Content-Type: application/json' \
-d '{"provider_id": "<PROVIDER_UUID>"}' | python3 -m json.toolIf the response contains a redirect URL, the setup is working. Tell the user they can open that URL in a browser to complete the MockSAML login (default user: jackson@example.com).
No teardown needed. Be aware:
supabase stop && supabase startreplaces the auth container (loses SAML env vars) — use./supabase/start-with-saml.shinstead, which re-injects them automaticallysupabase db resetwipes SSO provider registrations — use./supabase/start-with-saml.sh --resetthen rerun from step 8