Cannot log in to CalDAV after creating Stalwart user

Issue Description

I’m connecting to my CalDAV account but the server keeps rejecting me with a HTTP 403 error. I’ve tried it through a CalDAV-compatible task management app, but also via a simple HTTPS call to /dav/cal with basic auth credentials. These credentials work fine when logging in through the web UI.

Expected Behavior

CalDAV task sync should work, or at the very least I should get a HTTP 2xx response when calling that endpoint.

Actual Behavior

I’m getting a HTTP 403 error.

Reproduction Steps

  1. Set up a user account in the Stalwart web UI
  2. Use those credentials to do a basic auth call to /dav/cal, or try to configure the account in a task management app that supports CalDAV

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

The 403 is almost certainly a missing role on the account. The built-in User role does include all CalDAV permissions (dav-cal-*), but only if the account actually has that role assigned. A freshly created account with no role assigned gets no CalDAV permissions, which produces a 403.

Here’s what to check and fix:

  1. Check the account’s role - In the WebUI, go to Management > Directory > Accounts, open the user’s account, and look at the roles field. It should be set to User (the built-in user role). If it’s blank or set to something custom that doesn’t include DAV permissions, that’s the cause.

  2. Assign the User role - Edit the account and set the role to User. The built-in user role grants all dav-cal-*, dav-card-*, and dav-file-* permissions, which are exactly what CalDAV access requires.

  3. Check the default role setting - If you want all new accounts to get the User role automatically, verify that defaultUserRoleIds is set correctly in the Authentication singleton (WebUI: Settings > Authentication > General). If that’s not set, newly created accounts won’t have any role unless one is explicitly assigned.

The correct URL for CalDAV is /dav/cal/<account_name> (e.g. /dav/cal/alice), not just /dav/cal - bare path requests without a username segment may also 403 for a different reason, so make sure your client or test call includes the account name.

Relevant docs:

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong. If you found it useful, mention @helpbot in any reply to ask follow-up questions and the bot will respond again.

CalDAV resources are per-user: the calendar home is /dav/cal/, not bare /dav/cal, and clients should point at /.well-known/caldav and use PROPFIND for discovery rather than a plain GET (a raw GET only works on a specific event resource). See stalw.art/docs/http/webdav.

A 403 specifically (rather than 404/405) points at an access-control failure, the authenticated user isn’t the owner of, or hasn’t been granted access to, the calendar account in the path. Can you share the exact URL your client is using, the method, and whether the username in the path matches the account you authenticated as? The default user role does include CalDAV access, so a stock account should be able to reach its own calendars.

Thanks for getting back to me. However, as this was a month ago, I unfortunately already disposed of the test instance where this was an issue.

For the benefit of other users finding this thread: you mention that /dav/cal/ and not /dav/cal is the calendar home. But the documentation you link to writes the following:

Calendar data managed via CalDAV is available under the /dav/cal path.

Perhaps adding a trailing slash here will reduce confusion.

Regardless, in the future I’ll use the standardized /.well-known/caldav endpoint as you suggest.