Security
EventStoreDB supports basic authentication for HTTP API calls, and access control lists (ACL).
Authentication
Creating users
EventStoreDB supports basic HTTP authentication to internal users. You create these users with the HTTP API or the admin console. You need to use the credentials of the default user in the request, which has the username of admin
, and the password of changeit
.
When using the HTTP API, you can send the following JSON payload to the server:
{
"LoginName": "adminuser",
"FullName": "EventStore Admin",
"Groups": [
"$admins",
"DataScience"
],
"Password": "aVerySecurePassword"
}
curl -i -d "@new-user.json" "http://127.0.0.1:2113/users" \
-H "Content-Type:application/json"
HTTP/1.1 201 Created
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Requested-With, X-Forwarded-Host, X-Forwarded-Prefix, X-PINGOTHER, Authorization, ES-LongPoll, ES-ExpectedVersion, ES-EventId, ES-EventType, ES-RequiresMaster, ES-HardDelete, ES-ResolveLinkTos
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ES-Position, ES-CurrentVersion
Location: http://127.0.0.1:2113/users/adminuser
Content-Type: application/json; charset=utf-8
Server: Mono-HTTPAPI/1.0
Date: Thu, 23 Aug 2018 09:08:40 GMT
Content-Length: 90
Keep-Alive: timeout=15,max=100
{
"loginName": "adminuser",
"success": true,
"error": "Success",
"msgTypeId": 50
}
Once you have added users, you can use their details with requests.
If you were to use the wrong user or no user when a request requires one, you receive a 401 Unauthorized
response.
curl -i 'http://127.0.0.1:2113/streams/$all' -u admin:password
HTTP/1.1 401 Unauthorized
Access-Control-Allow-Methods:
Access-Control-Allow-Headers: Content-Type, X-Requested-With, X-Forwarded-Host, X-Forwarded-Prefix, X-PINGOTHER, Authorization, ES-LongPoll, ES-ExpectedVersion, ES-EventId, ES-EventType, ES-RequiresMaster, ES-HardDelete, ES-ResolveLinkTos
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ES-Position, ES-CurrentVersion
WWW-Authenticate: Basic realm="ES"
Content-Type:
Server: Mono-HTTPAPI/1.0
Date: Thu, 23 Aug 2018 09:27:34 GMT
Content-Length: 0
Keep-Alive: timeout=15,max=100
As you pass the username and password in the request we recommend you to enable SSL to encrypt the user information. Read this guide for instructions.
Access control lists
Alongside authentication, EventStoreDB supports per stream configuration of Access Control Lists (ACL). To configure the ACL of a stream go to its head and look for the metadata
relationship link to fetch the metadata for the stream.
To set access control lists over HTTP you can post to the metadata stream as with setting any other metadata. You can also set Access Control Lists for a stream in the admin UI.
ACL example
The ACL below gives writer
read and write permission on the stream, while reader
has read permission on the stream. Only users in the $admins
group can delete the stream or read and write the metadata.
The request body placed in the file named metadata.json:
[
{
"eventId": "7c314750-05e1-439f-b2eb-f5b0e019be72",
"eventType": "$user-updated",
"data": {
"readRole": "$all",
"metaReadRole": "$all"
}
}
]
Then, when you execute HTTP request as follows:
curl -i -d @metadata.json http://127.0.0.1:2113/streams/newstream/metadata \
--user admin:changeit \
-H "Content-Type: application/vnd.eventstore.events+json"
You get a confirmation from the server:
HTTP/1.1 201 Created
Access-Control-Allow-Methods: GET, POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Requested-With, X-Forwarded-Host, X-Forwarded-Prefix, X-PINGOTHER, Authorization, ES-LongPoll, ES-ExpectedVersion, ES-EventId, ES-EventType, ES-RequiresMaster, ES-HardDelete, ES-ResolveLinkTos
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ES-Position, ES-CurrentVersion
Location: http://127.0.0.1:2113/streams/%24%24newstream/0
Content-Type: text/plain; charset=utf-8
Server: Mono-HTTPAPI/1.0
Date: Tue, 18 Sep 2018 09:38:56 GMT
Content-Length: 0
Keep-Alive: timeout=15,max=100
Default ACL
TIP
All these examples assume you have created a user named ouro
with password ouroboros
.
If you try to access the $settings
stream as an unauthorized user, the server returns a 401 response.
curl -i http://127.0.0.1:2113/streams/%24settings \
-u ouro:ouroboros
HTTP/1.1 401 Unauthorized
Access-Control-Allow-Methods: POST, DELETE, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Requested-With, X-PINGOTHER, Authorization, ES-LongPoll, ES-ExpectedVersion, ES-EventId, ES-EventType, ES-RequiresMaster, ES-HardDelete, ES-ResolveLinkTo, ES-ExpectedVersion
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ES-Position
WWW-Authenticate: Basic realm="ES"
Content-Type: text/plain; charset=utf-8
Server: Mono-HTTPAPI/1.0
Date: Mon, 02 Mar 2015 15:21:27 GMT
Content-Length: 0
Keep-Alive: timeout=15,max=100
If you wanted to give ouro
access by default to system streams, POST the following JSON:
{
"$userStreamAcl": {
"$r": "$all",
"$w": "ouro",
"$d": "ouro",
"$mr": "ouro",
"$mw": "ouro"
},
"$systemStreamAcl": {
"$r": ["$admins", "ouro"],
"$w": "$admins",
"$d": "$admins",
"$mr": "$admins",
"$mw": "$admins"
}
}
At which point ouro
can read system streams by default:
curl -i http://127.0.0.1:2113/streams/%24settings \
-u ouro:ouroboros
HTTP/1.1 200 OK
Access-Control-Allow-Methods: POST, DELETE, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Requested-With, X-PINGOTHER, Authorization, ES-LongPoll, ES-ExpectedVersion, ES-EventId, ES-EventType, ES-RequiresMaster, ES-HardDelete, ES-ResolveLinkTo, ES-ExpectedVersion
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ES-Position
Cache-Control: max-age=0, no-cache, must-revalidate
Vary: Accept
ETag: "1;-1296467268"
Content-Type: application/atom+xml; charset=utf-8
Server: Mono-HTTPAPI/1.0
Date: Mon, 02 Mar 2015 15:25:17 GMT
Content-Length: 1286
Keep-Alive: timeout=15,max=100
You can also limit ACLs on particular streams which are then merged with the default ACLs.
{
"$acl": {
"$r": ["reader", "also-reader"]
}
}
If you add the above to a stream's ACL, then it overrides the read permission on that stream to allow reader
and also-reader
to read streams, but not ouro
, resulting in the effective ACL below.
{
"$acl": {
"$r": ["reader", "also-reader"],
"$w": "ouro",
"$d": "ouro",
"$mr": "ouro",
"$mw": "ouro"
}
}
WARNING
Caching is allowed on a stream if you have enabled it to be visible to $all
. This is as a performance optimization to avoid having to set cache=private
on all data. If people are bookmarking your URIs and they were cached by an intermediary then they may still be accessible after you change the permissions from $all
. While clients should not be bookmarking URIs in this way, it's an important consideration.