RealComposer
ExpoSupabaseSecurity & Secret Vault

Protect Supabase Service Role Key in Expo

Privileged Supabase reads for Expo without service_role on device

Direct Answer & Architecture Summary

The Supabase service_role key bypasses row level security, so it must never appear in an Expo app or OTA update. Keep the anon key in the app for normal queries and send privileged reads to a RealComposer pipeline that holds service_role in the vault and returns filtered fields.

Security LevelAES-256-GCM Vault
Edge LatencySub-10ms Response
InfrastructureZero Server Maintenance
The Problem Solved

Why service_role keys must stay off Expo devices

Some features, such as leaderboards or admin counts, need queries that row level security would block. Putting service_role in the app solves it quickly but hands every user full read and write access to the database.

Critical Security & Operational Risks:
  • Full database access from a key extracted from the bundle
  • Row level security bypassed for every client
  • Rotation requiring a forced app update
Architecture & Step-by-Step Implementation

How RealComposer Solves This at the Edge

1

Store credentials in Secret Vault

Save SUPABASE_SERVICE_ROLE_KEY in RealComposer so the value never enters the Expo project.

2

Configure the edge pipeline

Add the upstream steps with vault header injection, set allowed origins, and map only the fields the screen binds.

3

Fetch privileged data from Expo

Call your workspace edge URL with a restricted rc_live_ client token.

                    const res = await fetch('https://realcomposer.com/v1/workspace/protect-supabase-service-role-key-expo', {
  headers: { Authorization: 'Bearer rc_live_client_token' },
});
const { leaders } = await res.json();
                  
Payload Slimming Comparison
37% Bandwidth Reduction
Raw Upstream Response161 B
              [
  {
    "display_name": "ada",
    "points": 980,
    "user_id": "u_1"
  },
  {
    "display_name": "grace",
    "points": 940,
    "user_id": "u_2"
  },
  {
    "display_name": "linus",
    "points": 910,
    "user_id": "u_3"
  }
]
            
RealComposer Slimmed Edge Payload101 B
              {
  "leaders": [
    {
      "name": "ada",
      "points": 980
    },
    {
      "name": "grace",
      "points": 940
    },
    {
      "name": "linus",
      "points": 910
    }
  ]
}
            

Recipe Specs

HTTP method
GET
Upstream calls
1
Edge cache TTL
60s
Client auth
Restricted client token
Mapped output fields
6
Payload
161 B to 101 B (-37%)
Call from Terminal or Client
curl -X GET "https://realcomposer.com/v1/workspace/protect-supabase-service-role-key-expo" \
  -H "Authorization: Bearer rc_live_client_token"
Frequently Asked Questions

Developer Questions & Troubleshooting

Is the Supabase anon key safe in Expo?

Yes, when row level security is enabled on every table. The anon key is designed to be public; service_role is not.

Why cache the leaderboard for 60 seconds?

Every user sees the same top three, so a short edge cache serves thousands of requests from one Supabase query.

Sources & Definitions Used in This Answer

Instant Deployment

Deploy this Expo + Supabase Recipe

Clone this pre-configured pipeline into your RealComposer workspace in one click. We pre-populate upstream URLs, headers, and mapping rules.

CLONE THIS RECIPE
Related Architecture Recipes