Hi all. I just finished setting up a sync between our Azure AD groups and Cloudflare Access. We're moving more internal tools behind Access and needed to keep groups updated automatically.
I used the Access API and Microsoft Graph. It’s working, but I’m a bit nervous about missing an edge case. Has anyone else done this? I’m especially curious about:
- How you handle nested groups in Azure AD.
- If there's a recommended sync interval to avoid hitting API limits.
- Any logging or alerting you set up to catch sync failures.
I want to make sure it’s robust before we rely on it for production access.
learning every day
I've run a similar sync for about 18 months. For nested groups, you must actively choose to expand them via the `$expand=members` query parameter in Microsoft Graph, and you need the `GroupMember.Read.All` permission. The API won't recursively resolve them by default, so your code needs to handle the traversal, which can get expensive.
On interval: don't use a simple timer. We use a delta query on the `/groups` endpoint, watching for changes, and then only sync the modified groups. This keeps calls minimal. For a full sync backup, we run it weekly during off-hours.
For logging, every sync run writes a summary (groups added/removed, member counts) to a dedicated log stream. We also monitor for HTTP 429s from Graph and have a CloudWatch alarm if the error rate from our sync function exceeds 1% over a 15-minute period. The most common failure we see is timeouts on groups with very large membership.
every dollar counts
Nice work getting that set up! The nested groups part is tricky - we ended up adding a recursion depth limit in our code just in case. Graph kept timing out for a user in a group, in a group, in another group... you get the idea.
What did you use to actually run the sync? We started with a cron job but moved it to a serverless function, which made the error handling a bit easier to manage.
For failures, we send a Slack message to our team channel for any 400/500 errors. It's not fancy but it gets our attention!
The delta query approach is solid, but Graph's delta tokens can expire after a few days. If your function crashes and misses a rotation, you'll be doing a full sync anyway. I'd still schedule a full sync nightly as a failsafe, even if it's just to validate the delta state.
On nested groups, you can't just rely on the API's `$expand`. You'll need to implement a cache, otherwise you'll hammer Graph resolving the same parent groups every sync cycle. Store the group-to-member relationships locally and update incrementally.
And for the love of all that's simple, don't go serverless unless you enjoy debugging cold starts during a critical access outage. A container on a self-hosted runner with some basic retry logic is far more predictable.
null