Here is one thread related to this unending problem that other platforms don’t have (According to Claude). I realize my app is pushing the limits but maybe a better long term fix is warranted? At this stage there is no way my App would be SCORM or HIPPA compliant. Please consider. I have so many “workarounds” now that I fear the worst if I decide to scale with Base44 rather than to rebuild on a more robust stack.
The setup Building a public-facing booking flow on Base44. Anonymous booking visitors can't read Brand records via asServiceRole due to RLS. To bridge the gap, I built a new entity PublicBrandSnapshot (read: open, write: super_admin only). A function updatePublicBrandSnapshot rebuilds the cache for a given brand_id. A function backfillPublicBrandSnapshots iterates all brands and invokes the per-brand updater for each.
App: Telos (ID: 68acb57f0254697dfe7fbbfe) App Link: https://app.base44.com/apps/68acb57f0254697dfe7fbbfe/editor/preview
May 2, 4:24 PM
Thanks for the detailed setup description, Ed! I can see the pattern you're using here — a public snapshot entity as a workaround for the
asServiceRoleRLS issue. Looks like a solid architectural approach given the bug you're working around.
I notice you have an open ticket (#69ee860a50bd3c668b174ce8) that's already been escalated regarding the
asServiceRoleRLS bypass issue. It sounds like this ticket is related to the same underlying problem.
It seems like your message got cut off — "More to come" suggests you were about to share more details. What did you want to add or ask about? For example:
Are you hitting an issue with the
updatePublicBrandSnapshotor
backfillPublicBrandSnapshotsfunctions?
Is there a specific error you're seeing?
Do you need help with the logic or structure of the snapshot pattern?
Go ahead and share the rest — happy to help!
May 2, 4:24 PM
The problem When backfill calls asServiceRole.functions.invoke('updatePublicBrandSnapshot', { brand_id }), the inner function's auth.me() returns a synthetic service user (service+...@no-reply.base44.com, role=admin, no workspace_id). Inside the function, base44.asServiceRole.entities.Brand.get(brand_id) returns 404 "not found" for every brand — even brands that demonstrably exist and are owned by the calling admin.
May 2, 4:24 PM
This is really helpful detail, Ed. What you're describing —
asServiceRolereturning 404s on entity reads inside a function invoked by another function via
asServiceRole— sounds like it could be related to the same bug you already have escalated in ticket #69ee860a50bd3c668b174ce8.
The key observation here is the chained service role context: when
backfillPublicBrandSnapshotscalls
functions.invoke('updatePublicBrandSnapshot', { brand_id })via
asServiceRole, the inner function receives the synthetic service user context — but it seems that context isn't carrying the right app/workspace scope needed to resolve Brand records.
A few things worth noting:
The 404 vs. permission error distinction — if it were a pure RLS block you'd typically expect a 403 or empty result, not a 404. A 404 suggests the entity lookup itself is failing, possibly because the service role context in the inner function is scoped to the wrong app or is missing workspace context entirely.
The synthetic service user having no
workspace_idis a red flag — Brand records may be workspace-scoped, and without that context the lookup could be resolving against the wrong namespace.
Workaround to test: Instead of chaining
asServiceRole.functions.invoke, try having
backfillPublicBrandSnapshotsdo the Brand reads and snapshot writes directly within itself, without delegating to the inner function. This would tell you whether the issue is specifically with the chained invocation context vs. something else.
Given this is a deeper platform-level issue with chained
asServiceRolefunction calls, I'd strongly recommend adding this specific detail — the chained invocation pattern and the 404 behavior — as a follow-up in your existing escalated ticket (#69ee860a50bd3c668b174ce8) so the team investigating has the full picture.
Would you like help structuring that update, or is there more you wanted to share first?
May 2, 4:24 PM
let me post all the statements before you respond. Thanks
May 2, 4:24 PM
Got it, go ahead!
May 2, 4:24 PM
What we ruled out The brand records definitely exist — Brand.list() returns them with valid IDs, names, workspace_ids, and owner_user_ids. The IDs from list are then passed directly to get and fail. Audit confirmed all required fields are populated. Auth gate passes. Workspace filtering works correctly. asServiceRole bypass on writes works (the snapshot entity itself has been tested separately).
May 2, 4:24 PM
Understood, standing by for the rest!
May 2, 4:25 PM
The specific contradiction Brand.list() and Brand.get(brand_id) should be consistent for the same auth context. They aren't. With the same exact ID, list returns the record but get returns 404. This happens both with base44.entities.Brand.get(...) and base44.asServiceRole.entities.Brand.get(...). Identical behavior across both paths suggests something deeper than RLS.
May 2, 4:25 PM
Got it, keep going!
May 2, 4:25 PM
The question for Support Why does asServiceRole.entities.Brand.get(brand_id) return 404 inside a function that was invoked via asServiceRole.functions.invoke(), when the brand_id was obtained from Brand.list() in the calling function moments earlier? Is service-to-service function invocation supposed to preserve a usable auth context for entity reads? Is there a recommended pattern for one function to call another function with admin-level entity-read privileges?
May 2, 4:25 PM
Thanks for laying that out so clearly, Ed. I have the full picture now.
The contradiction you've identified is precise and well-documented:
Brand.list()and
Brand.get(brand_id)returning inconsistent results for the same auth context, with the same ID, is a platform-level bug — not something you can architect around at the app level.
To directly answer your questions based on what's documented:
Is service-to-service invocation supposed to preserve a usable auth context? The SDK docs indicate
createClientFromRequestin a backend function extracts auth from injected headers, and
asServiceRoleshould provide admin-level access. There's no documented caveat about chained invocations degrading that context — so what you're experiencing appears to be an undocumented failure mode.
Is there a recommended pattern for one function calling another with admin-level reads? There isn't a documented pattern specifically for this scenario, which itself is worth flagging.
Given that this is clearly related to your already-escalated ticket (#69ee860a50bd3c668b174ce8), I'd recommend adding this as a follow-up there with exactly what you've written here. The team investigating that bug needs to know:
list()vs
get()inconsistency with identical IDs and auth context
The chained
asServiceRole.functions.invoke()pattern as the trigger
That both
entities.Brand.get()and
asServiceRole.entities.Brand.get()fail identically — ruling out RLS as the cause
Your documentation here is excellent and gives the engineering team exactly what they need to reproduce and diagnose this. Shall I escalate this ticket and link it to the existing one?
May 2, 4:25 PM
Identifying details App ID: 68acb57f0254697dfe7fbbfe. My user: edferrigan@gmail.com (super_admin). Functions involved: backfillPublicBrandSnapshots, updatePublicBrandSnapshot. A specific failing brand_id you can investigate: 69a5ff8c42fa09d7c5b2b7e6 (EFC, in my workspace 6903ce3d04c105a16123f6ec, owned by my user 68acb57f0254697dfe7fbbff). Diagnostic logs in the function dashboard tagged [updatePublicBrandSnapshot] DIAG.
May 2, 4:25 PM
Thanks Ed — that's everything the team needs to investigate. Let me escalate this now with all the details you've provided.
May 2, 4:25 PM
Following up on ticket #69ee860a50bd3c668b174ce8 with new evidence. Implemented the bot's recommended workaround: inlined the snapshot-build logic directly inside backfillPublicBrandSnapshots so it no longer chains asServiceRole.functions.invoke to a second function. Brand reads under admin user context now work — all 11 brands in my workspace were read successfully.
May 2, 4:37 PM
But the writes failed. asServiceRole.entities.PublicBrandSnapshot.create() returns "Permission denied for create operation on PublicBrandSnapshot entity" for every brand. The entity's create RLS is restricted to super_admin only. My user (edferrigan@gmail.com) IS super_admin. asServiceRole should bypass RLS entirely.
May 2, 4:37 PM
This appears to be the same chained-asServiceRole pattern surfacing on the write path now instead of the read path. Reads worked when un-chained; writes failed even un-chained. Suggests asServiceRole is unreliable in this app for both reads AND writes, regardless of chaining.
May 2, 4:37 PM
App ID: 68acb57f0254697dfe7fbbfe. Function: backfillPublicBrandSnapshots. Entity: PublicBrandSnapshot. I'm pausing booking-flow work until I hear from a human handler. Happy to provide additional logs or test cases. Thanks.
May 2, 4:38 PM
Stephen
Support Team
Hi Ed,
This is a platform architecture constraint rather than a bug. When a backend function calls
asServiceRole.functions.invoke('updatePublicBrandSnapshot', ...), the inner function receives a bare HTTP request with no auth headers forwarded.
createClientFromRequest(req)inside the inner function has no app context to work from, so all entity operations fail, including
asServiceRoleones. That's why
Brand.get()returns 404 for IDs that
Brand.list()returned moments earlier — the outer and inner functions are running with completely different auth contexts.
The fix is to stop treating
updatePublicBrandSnapshotas something you call from another function. Move the Brand read and snapshot upsert logic directly into
backfillPublicBrandSnapshotsas an inline loop.
updatePublicBrandSnapshotcan stay as a standalone HTTP-callable function for single-brand cache refreshes triggered from the frontend or a scheduled automation, but it should not be invoked from another backend function.
Here's the prompt to restructure the backfill:
In
backfillPublicBrandSnapshots, replace the loop that calls
asServiceRole.functions.invoke('updatePublicBrandSnapshot', { brand_id })with inline logic. For each brand returned by
Brand.list(), directly read the brand record and upsert the corresponding
PublicBrandSnapshotentry, all within this function using
asServiceRole. Remove the
invokecall entirely. Do not modify
updatePublicBrandSnapshotitself.
Once restructured, the backfill will run entirely within a single auth context and the 404 issue will be gone.
Let us know how it goes.
Best regards, Stephen | Base44 Technical Support
May 2, 8:48 PM
Thanks Stephen. Quick clarification: we already restructured backfill to inline the logic per the bot's earlier guidance, before your reply. After that change, all 11 brand reads succeeded under regular admin auth — the 404s are gone. But all 11 PublicBrandSnapshot writes still failed with "Permission denied for create operation" via asServiceRole.entities.PublicBrandSnapshot.create(). The entity's create RLS is super_admin only, and my user is super_admin. Is the write-side failure a sep
May 3, 11:23 AM
Is the write-side failure a separate issue, or does your recommendation also resolve it once a single auth context is established?
May 3, 11:24 AM
Terryon
Support Team
Hi Ed,
It’s good to hear that the reads are functioning correctly after inlining the logic.
Regarding the write failure, I want to clarify how
asServiceRoleis designed to function. It is supposed to bypass RLS (Row Level Security) entirely, regardless of the specific rules in place (such as
super_adminrestrictions). If
asServiceRole.entities.PublicBrandSnapshot.create()is returning a "Permission denied" error, it suggests a platform-level issue where the bypass isn't being applied correctly to writes in your application.
This appears to be a separate anomaly from the chained invocation problem we discussed. To help us narrow down the cause, could you provide the following details:
Exact RLS Configuration: Can you confirm the specific
createrule for
PublicBrandSnapshot? Is it currently set to
user_condition: { role: 'super_admin' }or a different parameter?
Frontend Test: If you call
entities.PublicBrandSnapshot.create()directly from the frontend (without using
asServiceRole) while logged in as your user, does it work? This will help us determine if the failure is exclusive to the
asServiceRolecontext within a function.
Diagnostic Logs: Does the function dashboard show any additional metadata or error details beyond the standard "Permission denied" message?
Since this is the second unexpected behavior involving
asServiceRolein this app, getting these details will be essential for our investigation.
Best regards,
Terry | Base44 Technical Support
May 3, 12:49 PM
MESSAGE 1 of 5:
Hi Terry — Ed Ferrigan, picking back up on this thread. Sorry for the delay. I have answers to all three of your questions, including a focused diagnostic test that isolates the failure mode. Sending across multiple messages so each fits.
May 5, 5:40 PM
MESSAGE 2 of 5:
Q1: Exact RLS create rule for PublicBrandSnapshot:
"create": { "user_condition": { "role": "super_admin" } }
Update/delete are identical. Read is open ({}).
Calling user (edferrigan@gmail.com) is super_admin. So per the rule, this user should be able to create.
May 5, 5:40 PM
MESSAGE 3 of 5:
Q2: Frontend test — user-scoped (NOT asServiceRole):
Called base44.entities.PublicBrandSnapshot.create({brand_id:"TEST_..."}) while authenticated as super_admin.
Result: SUCCESS. Record created with id 69fa7f3216f3799192b87ee2, created_by_id matched my user. Record deleted afterwards.
So the RLS rule itself works correctly through the user-scoped path.
May 5, 5:40 PM
MESSAGE 4 of 5:
Q3: asServiceRole test with full error capture:
Built diagnostic function (diagPublicBrandSnapshotWrite) that calls base44.asServiceRole.entities.PublicBrandSnapshot.create() with identical payload, same authenticated session.
Result: 403. Full error: { message: "Permission denied for create operation on PublicBrandSnapshot entity", name: "Base44Error", status: 403 }
No code, no responseData, no cause. Function logs show ZERO [diagPBS] console.log lines fired — only Deno star
May 5, 5:41 PM
Deno startup logs. The 403 appears to be thrown by the RLS layer before the function body executes.
MESSAGE 5 of 5:
Summary of the contradiction:
Same user (super_admin)
Same RLS rule
User-scoped: works
asServiceRole: 403 Permission denied
asServiceRole is not satisfying user_condition: super_admin on this entity — it appears to be evaluated as if no role is present.
Diag function diagPublicBrandSnapshotWrite is left deployed if you want to run more tests. Happy to add more ins
May 5, 5:42 PM
Yelyzaveta
Support Team
Hi there!
Thank you for your incredibly detailed breakdown. Your identification of the failure mode—specifically how the user-scoped path works while the asServiceRole path returns a 403 Forbidden—was instrumental in pinpointing the root cause.
I sincerely apologize for any confusion caused by our earlier responses. After a thorough review of the platform architecture, we’ve determined this is not a platform bug but relates to how the asServiceRole context is evaluated against RLS rules.
The core issue concerns how asServiceRole interacts with Role-Based Access Control (RBAC) within your RLS setup.
The Conflict: Your RLS rule for the PublicBrandSnapshot entity explicitly requires a super_admin role:
{"user_condition": {"role": "super_admin"}} The asServiceRole Context: When you use asServiceRole inside a backend function, the platform creates a synthetic service user. While this user has elevated privileges, it does not automatically inherit the super_admin role of the original user who triggered the function.
The Requirement: For asServiceRole to bypass or satisfy RLS rules that check for specific roles, the entity’s RLS must include permissions for the admin role.
Because your rule strictly requires super_admin, the service role—which identifies as an admin level service user—is being blocked by the RLS layer before the function logic even executes.
The Solution: To enable your backfillPublicBrandSnapshots function to write to the PublicBrandSnapshot entity using asServiceRole, you should update the RLS rule to include the admin role:
{"user_condition": {"role": "admin"}} Since super_admin encompasses admin permissions, your manual frontend tests will remain successful, and the asServiceRole context will now have the necessary authorization to perform create and update operations.
Given that you’ve already inline the logic to avoid chained invocation issues, updating this RLS rule should be the final step to enable your booking flow.
We appreciate your patience and the professional approach you took in documenting these findings. Please let us know if you encounter any further issues once the RLS is updated. We're here to help!
Best regards,
Liz | Base44 Support Team
May 6, 1:06 AM
1 of 7 Q1: Stephen's earlier reply (5/3) said chained asServiceRole.functions.invoke calls forward no auth headers, so the inner function has no auth context at all. Your reply says the synthetic user IS authenticated, just at admin level. Are these both correct (different mechanisms for chained vs direct asServiceRole), or is one of them outdated?
May 6, 9:10 AM
Q2: Does the synthetic admin user created by asServiceRole have a workspace_id? Our canonical RLS shape pairs admin role with a workspace_id match (admin AND data.workspace_id == {{user.data.workspace_id}}). If the synthetic user has no workspace_id, that clause still blocks the write. Should we use unscoped admin, or is there a synthetic workspace_id we can match?
May 6, 9:11 AM
3 of 6 Q3: If we add an unscoped admin clause to satisfy asServiceRole, that clause also lets any real admin user from any workspace create records on this entity. For PublicBrandSnapshot the risk is low (data is public by design and our function scope-filters before writing). But is that the intended pattern, or is there a way to authorize asServiceRole specifically without weakening the rule for real users?
May 6, 9:11 AM
4 of 6: Q4: Is this an entity-by-entity fix, or platform-wide? We have ~17 admin save sites that call updatePublicBrandSnapshot from admin browser context (real super_admin user, not asServiceRole). Should those continue working under the current rule, and we only need to add the admin clause for the asServiceRole-internal write paths?
May 6, 9:12 AM
5 of 6: Q5: Are there other entities in our app where asServiceRole writes will silently fail under super_admin-only RLS? If so, we'd want to audit them deliberately rather than discover the failures one at a time. Any guidance on identifying the affected entities would save us troubleshooting cycles.
May 6, 9:12 AM
Once I understand the answers, I'll update PublicBrandSnapshot's RLS with the right shape and verify the backfill works. Thanks for the patience on the back-and-forth — getting this right at the architectural level matters more than getting it right just for one entity. Thank you so much for your support on this!
May 6, 9:13 AM
Fode
Support Team
Hi Ed,
Thank you for the structured questions, I have direct answers to all five.
Q1: Stephen's reply vs. Liz's reply — which is correct?
Both are correct, but they describe two separate failure modes you hit sequentially.
Stephen's explanation applies to the chained invocation phase. When
backfillPublicBrandSnapshotscalled
asServiceRole.functions.invoke('updatePublicBrandSnapshot', ...), the inner function received a raw HTTP request with no forwarded auth headers.
createClientFromRequest(req)inside that function had no app or workspace context, so all entity operations failed — including
asServiceRoleones. That's the source of the original 404s on Brand reads.
Liz's explanation applies after you inlined the logic. With a single function and a direct
asServiceRolecontext, auth is intact — but
asServiceRolecreates a synthetic service user whose role evaluates as
admin, not
super_admin. Your RLS rule
{"user_condition": {"role": "super_admin"}}does not match that synthetic user, so writes return 403. Reads worked because your Brand read RLS doesn't enforce a role check that blocks
admin. These are genuinely separate mechanisms and you've now hit both.
Q2: Does the synthetic admin user have a
workspace_id?
No. The synthetic user carries no
workspace_id. This means a compound rule like:
{"$and": [{"user_condition": {"role": "admin"}}, {"data.workspace_id": "{{user.data.workspace_id}}"}]} ...will always block the service user, because
{{user.data.workspace_id}}resolves to null for the synthetic user. For any entity where
asServiceRoleneeds to write, you need an unscoped
adminbranch (role check only, no workspace match) as a separate
$orcondition — not wrapped in an AND.
Q3: Is there a way to authorize
asServiceRolespecifically without weakening security for real users?
The platform does not provide a dedicated
asServiceRoleidentity token you can target in an RLS condition. The synthetic user presents as
role: admin, which is indistinguishable from a real admin user in RLS evaluation.
The safest pattern is an
$orstructure:
{"$or": [{"user_condition": {"role": "super_admin"}}, {"user_condition": {"role": "admin"}}]} For
PublicBrandSnapshotthis is fine — data is public by design and your function scope-filters before writing. For other entities where cross-workspace admin writes would be dangerous, the recommended workaround is to not rely on
asServiceRolewrites directly — instead, validate the scope in your function code and only write records that belong to the calling user's workspace before invoking the entity operation. This keeps the dangerous writes off the
asServiceRolepath entirely.
Q4: Entity-by-entity or platform-wide? Will your 17 admin save sites still work?
Entity-by-entity. Your 17 admin save sites call from the browser as a real authenticated
super_adminuser — they don't go through
asServiceRoleand will continue to satisfy the existing
super_adminrule unchanged. Adding the
$orwith an
adminbranch does not affect those browser-origin calls at all.
Q5: Which other entities will silently fail under
asServiceRolewrites?
There's no automated audit tool for this. We manually reviewed your entity schemas and identified the affected set, entities where at least one write operation has a
super_admin-only rule with no
adminbranch:
PublicBrandSnapshot— create, update, delete
AppConfig— create, update, delete
DebugLog— delete
Order— delete
Challenge— update, delete
Experiment— update, delete
SavedSection— update, delete
Cross-reference these against your backend functions: any function calling
asServiceRole.entities.<EntityName>.create/update/delete()on an entity in this list needs the
$orfix. Entities where RLS is open or uses
created_by/
workspace_idfield comparisons rather than a
super_adminrole check are not affected.
The fix for
PublicBrandSnapshotis:
{ "create": {"$or": [{"user_condition": {"role": "super_admin"}}, {"user_condition": {"role": "admin"}}]}, "read": {}, "update": {"$or": [{"user_condition": {"role": "super_admin"}}, {"user_condition": {"role": "admin"}}]}, "delete": {"$or": [{"user_condition": {"role": "super_admin"}}, {"user_condition": {"role": "admin"}}]} } Once that's deployed, the backfill should run cleanly end-to-end. Let us know how it goes.
Best regards, Fofo | Base44 Support
May 6, 12:07 PM
ran trace: What's confirmed: asServiceRole cannot read Brand or Contact in production. ContactActivity, User, and ServiceType work because their RLS happens to have unconditional admin/super_admin branches. Brand and Contact have the scoped-admin branch (which fails for the synthetic user).
May 7, 1:56 PM
The mitigating reality: The dev needs to confirm this, but in your app, who has role: admin versus role: user versus role: super_admin? If the only people with role: admin are platform operators (you in your super_admin capacity, plus maybe one or two trusted accounts), then in practice this branch only gets exercised by asServiceRole and there's no real exposure. But if role: admin is given to coaches by default, then this branch lets every coach read every other coach's brands.
May 7, 1:56 PM
That would be a serious privacy breach.
May 7, 1:57 PM
That was the AI. The answer is the entire app relies on other Coaches using it with users under them. SuperAdmin (me) and Admins (Coaches) and Users (Under Admins) same workspace. AI Suggested path: Path 1: Add an unscoped admin read branch to Brand and Contact RLS. The new read rule would look like: json"read": { "$or": [ { "user_condition": { "role": "super_admin" } }, { "user_condition": { "role": "admin" } }, { "$and": [ { "<OWNERSHIP>": "{{user.id}}" },
May 7, 2:01 PM
{ "data.workspace_id": "{{user.data.workspace_id}}" } ] } ] } What this means in practice:
The asServiceRole synthetic admin can now read brands and contacts (good — fixes the booking flow). A real human user with role: admin could ALSO read all brands and contacts across all workspaces (bad — this is a real privacy regression).
May 7, 2:02 PM
I gave Claude your entire thread. Not happy with this solution. Suggestions? Did it miss something?
May 7, 2:03 PM
Each coach and each users needs their own private entries across the board.
May 7, 2:05 PM
Surely there is a strategy for this. Can't image other apps not needing this?
May 7, 2:17 PM
Please read the attached PDF and offer any feedback before I make the decision to move ALL my code over to a new platform if this cannot be repaired. It has stopped me so many times I can't count. Exhausting to spend my time this way. I saw an interview with your founder and this seems like the very thing he wants to fix now and not wait.
May 7, 2:24 PM
example what I keep running up against: "We're in a familiar pattern. The Brand read bug doesn't just break Calendar sync. It also breaks the writer that's supposed to populate the snapshot that's supposed to work around the Brand read bug. If the writer also can't read Brand, we have a chicken-and-egg situation that may need a different approach entirely (passing brand data into the writer instead of the writer fetching it)."
May 7, 4:23 PM
Stephen
Support Team
Hi Ed,
Good news:
backfillPublicBrandSnapshotsis already structured correctly. The inline approach you applied uses the caller's own session for reads and only routes the write through
asServiceRole, which is exactly right.
The remaining issue is in
updatePublicBrandSnapshot. Even though it verifies the caller is an admin before doing anything, it then switches to
base44.asServiceRole.entities.Brand.get(brand_id)for the source read. That synthetic service user can't pass Brand's RLS, which is why it returns 404. The fix is straightforward: since you already have a verified admin caller, use their session for the Brand read.
In
updatePublicBrandSnapshot, change the
Brand.get()call from
base44.asServiceRole.entities.Brand.get(brand_id)to
base44.entities.Brand.get(brand_id). Do the same for the subsequent
ServiceType,
AppointmentSettings,
WorkingHours, and
BrandColorreads in that function. Only keep
asServiceRoleon the
PublicBrandSnapshotread and write calls at the end. The auth gate at the top of the function already confirms the caller is admin or super_admin, so using their session for source reads is safe and will satisfy Brand's RLS.
One separate thing worth noting: the
workspace_idscope in Brand's RLS rule uses
{{user.workspace_id}}, but for custom User fields the correct syntax is
{{user.data.workspace_id}}. The scoped-admin branch is likely silently failing for all real admin users. Your current setup works because
BrandManagerfilters by
owner_user_idat the app level rather than relying on RLS for scoping, but the RLS rule itself is not doing what it looks like it should. Worth fixing to avoid surprises down the road.
Let us know how it goes.
Best regards, Stephen | Base44 Technical Support
May 7, 5:19 PM
Please inform me if there is any chance there is anything going on behind the scenes to fix RSL or make it more robust with suggestions in the document I added to my last post, or to continue patching for users? Thanks, and I do appreciate your help but Im exhausted running into this same issue and Im convinced other tech stacks don't have this issue.
May 7, 5:48 PM
Suzanne
Support Team
Hi Ed,
Thank you for everything you have shared throughout this thread — your documentation has been exceptional and the PDF you attached has been noted and passed along.
I want to answer your question directly and honestly.
Regarding whether there is work happening behind the scenes to make asServiceRole more robust and to address the RLS limitations you have been hitting — I genuinely do not have visibility into the product roadmap from the support side, and I would not want to make promises I cannot stand behind. What I can tell you is that the pattern you have documented — asServiceRole not carrying workspace context, the synthetic admin user being indistinguishable from real admin users in RLS evaluation, the chicken-and-egg read/write dependency — is a well-articulated architectural limitation and your ticket represents some of the best evidence we have seen for why it needs to be addressed.
The most direct way to make sure this reaches the product team with the weight it deserves is to post it at (feedback.base44.com)[feedback.base44.com] with the specifics you have outlined. The product team actively review that board and use it to prioritise what gets built.
On the immediate technical path forward — Stephen's latest suggestion to use the caller's session for Brand reads rather than asServiceRole is the correct fix for updatePublicBrandSnapshot and should unblock your backfill without the privacy risk of widening the RLS rule. The {{user.data.workspace_id}} correction he flagged is also worth applying.
Your frustration is completely understood and your feedback matters.
Kind regards, Suzanne | Base44
2:21 AM
Hi Stephen — your fix worked for the source reads. Brand, ServiceType, AppointmentSettings, WorkingHours, BrandColor all return data now and the snapshot payload builds correctly. Thank you.
The function then failed at the final step: PublicBrandSnapshot.create returned 403 "Permission denied" because asServiceRole is synthetic admin, not super_admin. So I tried applying your same pattern to the snapshot write.
10:04 AM
Specifically: I changed the PublicBrandSnapshot existing-record lookup AND the create/update at the end from base44.asServiceRole.entities.PublicBrandSnapshot.* to base44.entities.PublicBrandSnapshot.*. The auth gate already verifies super_admin, so I expected the caller's session to satisfy the create RLS.
After that change, the function fails MUCH earlier — auth.me() itself returns 403.
10:04 AM
The 403 response body is a Cloudflare "Just a moment..." challenge page (HTML), not Base44's own auth response. Logs show:
[DIAG auth.me result: user_present=false auth_error=Request failed with status code 403] [Base44 SDK Error] 403: Request failed with status code 403 Error data: "<!DOCTYPE html>...<title>Just a moment...</title>..."
Reverting only the snapshot calls back to asServiceRole brings auth.me() back to working.
10:05 AM
Two questions:
Why does switching the PublicBrandSnapshot calls to the caller's session break auth.me() upstream? auth.me() runs before any entity calls. Is there something about mixing asServiceRole and caller-session calls in the same function that disrupts SDK initialization?
The Cloudflare challenge page in the response — that suggests an edge-layer intercept before Base44's auth runs. Expected?
10:06 AM
Bonus question: what's the recommended pattern for a function auth-gated to super_admin that needs to write to an entity whose create RLS only allows super_admin? Keep the write on asServiceRole and loosen the entity's RLS to allow admin? Or another approach?
Test details: brand_id 69a5ff8c42fa09d7c5b2b7e6 (EFC), caller edferrigan@gmail.com (super_admin), function updatePublicBrandSnapshot.
Thank you. — Ed
10:06 AM
Offline support, prioritized reply within 48h
Handled by a support specialist
Please authenticate to join the conversation.
In Review
Feature Request
About 14 hours ago

Ed Ferrigan
Get notified by email when there are changes.
In Review
Feature Request
About 14 hours ago

Ed Ferrigan
Get notified by email when there are changes.