github.com/cozy/cozy-stack@v0.0.0-20240327093429-939e4a21320e/docs/bitwarden.md (about) 1 [Table of contents](README.md#table-of-contents) 2 3 # Bitwarden 4 5 Cozy-stack exposes an API compatible with 6 [Bitwarden](https://github.com/bitwarden) on `/bitwarden`. 7 8 The author of the [unofficial Bitwarden-ruby 9 server](https://github.com/jcs/rubywarden) did some reverse engineering and 10 wrote a short [API 11 documentation](https://github.com/jcs/rubywarden/blob/master/API.md). 12 13 ## Setup 14 15 The signup is disabled, there is one account per Cozy instance, with the email 16 `me@<domain>`. When the user chooses his/her password (onboarding), an encryption key 17 is also generated to keep safe the secrets in the bitwarden vault. 18 19  20 21 A cozy organization is also created: it will be used to share some passwords 22 with the stack, to be used for the konnectors. 23 24  25 26 The bitwarden clients can connect to the cozy-stack APIs by setting their URL 27 to `https://<instance>/bitwarden`. 28 29 ## Routes for accounts and connect 30 31 ### POST /bitwarden/api/accounts/prelogin & POST /bitwarden/identity/accounts/prelogin 32 33 It allows the client to know the number of KDF iterations to apply when hashing 34 the master password. It can also tell if the login via OIDC is mandatory, if 35 the vault is empty (when both conditions are true, the onboarding process is a 36 bit different), and if flat or nested subdomains are used. 37 38 There are 2 routes for the same endpoint, as Bitwarden has moved from the first 39 to the second, and we want to ensure a smooth migration for clients. 40 41 #### Request 42 43 ```http 44 POST /bitwarden/identity/accounts/prelogin HTTP/1.1 45 Host: alice.example.com 46 Content-Type: application/json 47 ``` 48 49 ```json 50 { 51 "email": "me@alice.example.com" 52 } 53 ``` 54 55 #### Response 56 57 ```http 58 HTTP/1.1 200 OK 59 Content-Type: application/json 60 ``` 61 62 ```json 63 { 64 "Kdf": 0, 65 "KdfIterations": 10000, 66 "OIDC": false, 67 "HasCiphers": true, 68 "FlatSubdomains": true 69 } 70 ``` 71 72 ### POST /bitwarden/identity/connect/token 73 74 #### Request (initial connection) 75 76 ```http 77 POST /bitwarden/identity/connect/token HTTP/1.1 78 Host: alice.example.com 79 Content-Type: application/x-www-form-urlencoded 80 ``` 81 82 ``` 83 grant_type=password& 84 username=me@alice.example.com& 85 password=r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=& 86 scope=api offline_access& 87 client_id=browser& 88 deviceType=3& 89 deviceIdentifier=aac2e34a-44db-42ab-a733-5322dd582c3d& 90 deviceName=firefox& 91 clientName=Cozy& 92 devicePushToken= 93 ``` 94 95 If authentication with two factors is enabled on the instance and the 96 user not logged through a web session, this request will fail with a 97 400 status, but it will send an email with the code. The request can 98 be retried with an additional paramter: `twoFactorToken`. 99 100 **Note:** the `clientName` parameter is optional, and is not sent by the 101 official bitwarden clients (a default value is used). 102 103 #### Response 104 105 ```http 106 HTTP/1.1 200 OK 107 Content-Type: application/json 108 ``` 109 110 ```json 111 { 112 "client_id": "f05671e159450b44d5c78cebbd0260b5", 113 "registration_access_token": "J9l-ZhwP[...omitted for brevity...]", 114 "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkJDMz[...](JWT string)", 115 "expires_in": 3600, 116 "token_type": "Bearer", 117 "refresh_token": "28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf", 118 "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=", 119 "PrivateKey": null 120 } 121 ``` 122 123 #### Request (refresh token) 124 125 ```http 126 POST /bitwarden/identity/connect/token HTTP/1.1 127 Host: alice.example.com 128 Content-Type: application/x-www-form-urlencoded 129 ``` 130 131 ``` 132 grant_type=refresh_token& 133 client_id=browser& 134 refresh_token=28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf 135 ``` 136 137 #### Response 138 139 ```http 140 HTTP/1.1 200 OK 141 Content-Type: application/json 142 ``` 143 144 ```json 145 { 146 "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkJDMz[...](JWT string)", 147 "expires_in": 3600, 148 "token_type": "Bearer", 149 "refresh_token": "28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf", 150 "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=" 151 } 152 ``` 153 154 ### POST /bitwarden/api/accounts/password-hint 155 156 #### Request 157 158 ```http 159 POST /bitwarden/api/accounts/password-hint HTTP/1.1 160 Host: alice.example.com 161 Content-Type: application/json 162 ``` 163 164 ```json 165 { 166 "email": "me@alice.example.com" 167 } 168 ``` 169 170 #### Response 171 172 ```http 173 HTTP/1.1 200 OK 174 ``` 175 176 ### GET /bitwarden/api/accounts/profile 177 178 #### Request 179 180 ```http 181 GET /bitwarden/api/accounts/profile HTTP/1.1 182 Host: alice.example.com 183 ``` 184 185 #### Response 186 187 ```http 188 HTTP/1.1 200 OK 189 Content-Type: application/json 190 ``` 191 192 ```json 193 { 194 "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601", 195 "Name": "Alice", 196 "Email": "me@alice.example.com", 197 "EmailVerified": false, 198 "Premium": false, 199 "MasterPasswordHint": null, 200 "Culture": "en-US", 201 "TwoFactorEnabled": false, 202 "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=", 203 "PrivateKey": null, 204 "SecurityStamp": "5d203c3f-bc89-499e-85c4-4431248e1196", 205 "Organizations": [], 206 "Object": "profile" 207 } 208 ``` 209 210 ### PUT /bitwarden/api/accounts/profile 211 212 This route allows to change the profile (currently, only the hint for the 213 master password). It can also be called with a `POST` (I think it is used by 214 the web vault). 215 216 #### Request 217 218 ```http 219 PUT /bitwarden/api/accounts/profile HTTP/1.1 220 Host: alice.example.com 221 Content-Type: application/json 222 ``` 223 224 ```json 225 { 226 "masterPasswordHint": "blah blah blah" 227 } 228 ``` 229 230 #### Response 231 232 ```http 233 HTTP/1.1 200 OK 234 Content-Type: application/json 235 ``` 236 237 ```json 238 { 239 "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601", 240 "Name": "Alice", 241 "Email": "me@alice.example.com", 242 "EmailVerified": false, 243 "Premium": false, 244 "MasterPasswordHint": "blah blah blah", 245 "Culture": "en-US", 246 "TwoFactorEnabled": false, 247 "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=", 248 "PrivateKey": null, 249 "SecurityStamp": "5d203c3f-bc89-499e-85c4-4431248e1196", 250 "Organizations": [], 251 "Object": "profile" 252 } 253 ``` 254 255 ### POST /bitwarden/api/accounts/keys 256 257 This route is used to save a key pair (public and private keys), to be used 258 with organizations. 259 260 #### Request 261 262 ```http 263 POST /bitwarden/api/accounts/keys HTTP/1.1 264 Host: alice.example.com 265 Content-Type: application/json 266 ``` 267 268 ```json 269 { 270 "encryptedPrivateKey": "2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=", 271 "publicKey": "MIIBIjANBgkqhkiG9w...AQAB" 272 } 273 ``` 274 275 #### Response 276 277 ```http 278 HTTP/1.1 200 OK 279 Content-Type: application/json 280 ``` 281 282 ```json 283 { 284 "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601", 285 "Name": "Alice", 286 "Email": "me@alice.example.com", 287 "EmailVerified": false, 288 "Premium": false, 289 "MasterPasswordHint": null, 290 "Culture": "en-US", 291 "TwoFactorEnabled": false, 292 "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=", 293 "PrivateKey": "2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=", 294 "SecurityStamp": "5d203c3f-bc89-499e-85c4-4431248e1196", 295 "Organizations": [], 296 "Object": "profile" 297 } 298 ``` 299 300 ### POST /bitwarden/api/accounts/security-stamp 301 302 It allows to set a new security stamp, which has the effect to disconnect all 303 the clients. It can be used, for example, if the encryption key is changed to 304 avoid the clients to corrupt the vault with ciphers encrypted with the old key. 305 306 #### Request 307 308 ```http 309 POST /bitwarden/api/accounts/security-stamp HTTP/1.1 310 Host: alice.example.com 311 Content-Type: application/json 312 ``` 313 314 ```json 315 { 316 "masterPasswordHash": "r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=" 317 } 318 ``` 319 320 #### Response 321 322 ```http 323 HTTP/1.1 204 No Content 324 ``` 325 326 ### GET /bitwarden/api/accounts/revision-date 327 328 It returns the date of the last change on the server, as a number of 329 milliseconds since epoch (sic). It is used by the clients to know if they have 330 to do a sync or if they are already up-to-date. 331 332 #### Request 333 334 ```http 335 GET /bitwarden/api/accounts/revision-date HTTP/1.1 336 Host: alice.example.com 337 ``` 338 339 #### Response 340 341 ```http 342 HTTP/1.1 200 OK 343 344 1569571388892 345 ``` 346 347 ### PUT /bitwarden/api/settings/domains 348 349 This route is also available via a `POST`, for compatibility with the web vault. 350 351 #### Request 352 353 ```http 354 PUT /bitwarden/api/settings/domains HTTP/1.1 355 Host: alice.example.com 356 Content-Type: application/json 357 ``` 358 359 ```json 360 { 361 "equivalentDomains": [ 362 ["stackoverflow.com", "serverfault.com", "superuser.com"] 363 ], 364 "globalEquivalentDomains": [42, 69] 365 } 366 ``` 367 368 #### Response 369 370 ```http 371 HTTP/1.1 200 OK 372 Content-Type: application/json 373 ``` 374 375 ```json 376 { 377 "EquivalentDomains": [ 378 ["stackoverflow.com", "serverfault.com", "superuser.com"] 379 ], 380 "GlobalEquivalentDomains": [ 381 { "Type": 2, "Domains": ["ameritrade.com", "tdameritrade.com"], "Excluded": false }, 382 { "Type": 3, "Domains": ["bankofamerica.com", "bofa.com", "mbna.com", "usecfo.com"], "Excluded": false }, 383 { "Type": 42, "Domains": ["playstation.com", "sonyentertainmentnetwork.com"], "Excluded": true }, 384 { "Type": 69, "Domains": ["morganstanley.com", "morganstanleyclientserv.com"], "Excluded": true } 385 ], 386 "Object": "domains" 387 } 388 ``` 389 390 ### GET /bitwarden/api/settings/domains 391 392 #### Request 393 394 ```http 395 GET /bitwarden/api/settings/domains HTTP/1.1 396 Host: alice.example.com 397 ``` 398 399 #### Response 400 401 ```http 402 HTTP/1.1 200 OK 403 Content-Type: application/json 404 ``` 405 406 ```json 407 { 408 "EquivalentDomains": [ 409 ["stackoverflow.com", "serverfault.com", "superuser.com"] 410 ], 411 "GlobalEquivalentDomains": [ 412 { "Type": 2, "Domains": ["ameritrade.com", "tdameritrade.com"], "Excluded": false }, 413 { "Type": 3, "Domains": ["bankofamerica.com", "bofa.com", "mbna.com", "usecfo.com"], "Excluded": false }, 414 { "Type": 42, "Domains": ["playstation.com", "sonyentertainmentnetwork.com"], "Excluded": true }, 415 { "Type": 69, "Domains": ["morganstanley.com", "morganstanleyclientserv.com"], "Excluded": true } 416 ], 417 "Object": "domains" 418 } 419 ``` 420 421 ## Route for sync 422 423 ### GET /bitwarden/api/sync 424 425 The main action of the client is a one-way sync, which just fetches all objects 426 from the server and updates its local database. 427 428 #### Request 429 430 ```http 431 GET /bitwarden/api/sync HTTP/1.1 432 ``` 433 434 #### Response 435 436 ```http 437 HTTP/1.1 200 OK 438 Content-Type: application/json 439 ``` 440 441 ```json 442 { 443 "Profile": { 444 "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601", 445 "Name": "Alice", 446 "Email": "me@alice.example.com", 447 "EmailVerified": false, 448 "Premium": false, 449 "MasterPasswordHint": null, 450 "Culture": "en-US", 451 "TwoFactorEnabled": false, 452 "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=", 453 "PrivateKey": null, 454 "SecurityStamp": "5d203c3f-bc89-499e-85c4-4431248e1196", 455 "Organizations": [ 456 { 457 "Id": "38ac39d0-d48d-11e9-91bf-f37e45d48c79", 458 "Name": "Cozy", 459 "Key": "4.HUzVDQVAFc4JOpW3/j/QwZeET0mXOiDW5s/HdpxLZ2GFnGcxOm1FE4XD2p7XTSwORXO/Lo8y0A87UhXKEXzfHZmpJR04pbpUPr4NJbjRKv/cSkNFlvm0rIUw/m0Jkft/gew9v3QfkVSGdSZk5XIimwkTQ5WM+WCStxbQJIKAH+AoEA5q6t9mpNNlTAQvMgqs8u7CJwSjeZ7qbabfEUVX1HIPgxC3BtVUkySRSws/gUNeMwY23kAJJQYT+uuMooZUr7umU6YkEHG2RQZwCCjVHX4czxZRWsVo/xQOYoNr7DjgCf92D7OrJlFmDtQjzSy2BjotN6vn+1SwtHbeDILWaQ==", 460 "BillingEmail": "me@cozy.localhost", 461 "Plan": "TeamsAnnually", 462 "PlanType": 5, 463 "Seats": 2, 464 "MaxCollections": 1, 465 "MaxStorageGb": 1, 466 "SelfHost": true, 467 "Use2fa": true, 468 "UseDirectory": false, 469 "UseEvents": false, 470 "UseGroups": false, 471 "UseTotp": true, 472 "UsersGetPremium": true, 473 "Enabled": true, 474 "Status": 2, 475 "Type": 2, 476 "Object": "profileOrganization" 477 } 478 ], 479 "Object": "profile" 480 }, 481 "Folders": [ 482 { 483 "Id": "14220912-d002-471d-a364-a82a010cb8f2", 484 "Name": "2.tqb+y2z4ChCYHj4romVwGQ==|E8+D7aR5CNnd+jF7fdb9ow==|wELCxyy341G2F+w8bTb87PAUi6sdXeIFTFb4N8tk3E0=", 485 "RevisionDate": "2017-11-13T16:20:56.5633333", 486 "Object": "folder" 487 } 488 ], 489 "Ciphers": [ 490 { 491 "FolderId": null, 492 "Favorite": false, 493 "Edit": true, 494 "Id": "0f01a66f-7802-42bc-9647-a82600f11e10", 495 "OrganizationId": null, 496 "Type": 1, 497 "Login": { 498 "Uris": [ 499 { 500 "Uri": "2.6DmdNKlm3a+9k/5DFg+pTg==|7q1Arwz/ZfKEx+fksV3yo0HMQdypHJvyiix6hzgF3gY=|7lSXqjfq5rD3/3ofNZVpgv1ags696B2XXJryiGjDZvk=", 501 "Match": null 502 } 503 ], 504 "Username": "2.4Dwitdv4Br85MABzhMJ4hg==|0BJtHtXbfZWwQXbFcBn0aA==|LM4VC+qNpezmub1f4l1TMLDb9g/Q+sIis2vDbU32ZGA=", 505 "Password": "2.OOlWRBGib6G8WRvBOziKzQ==|Had/obAdd2/6y4qzM1Kc/A==|LtHXwZc5PkiReFhkzvEHIL01NrsWGvintQbmqwxoXSI=", 506 "Totp": null 507 }, 508 "Name": "2.zAgCKbTvGowtaRn1er5WGA==|oVaVLIjfBQoRr5EvHTwfhQ==|lHSTUO5Rgfkjl3J/zGJVRfL8Ab5XrepmyMv9iZL5JBE=", 509 "Notes": "2.NLkXMHtgR8u9azASR4XPOQ==|6/9QPcnoeQJDKBZTjcBAjVYJ7U/ArTch0hUSHZns6v8=|p55cl9FQK/Hef+7yzM7Cfe0w07q5hZI9tTbxupZepyM=", 510 "Fields": null, 511 "Attachments": null, 512 "OrganizationUseTotp": false, 513 "RevisionDate": "2017-11-09T14:37:52.9033333", 514 "Object": "cipher" 515 } 516 ], 517 "Collections": [ 518 { 519 "Id": "385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d", 520 "OrganizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79", 521 "Name": "2.PowfE263ZLz7+Jqrpuezqw==|OzuXDsJnQdfa/eMKxsms6Q==|RpEB7qqs26X9dqa+KaxSE5+52TFVs4dAdfU7DCu3QXM=", 522 "Object": "collection", 523 "ReadOnly": false 524 } 525 ], 526 "Domains": { 527 "EquivalentDomains": null, 528 "GlobalEquivalentDomains": null, 529 "Object": "domains" 530 }, 531 "Object": "sync" 532 } 533 ``` 534 535 ## Routes for ciphers 536 537 ### GET /bitwarden/api/ciphers 538 539 It retrieves the list of ciphers. 540 541 #### Request 542 543 ```http 544 GET /bitwarden/api/ciphers HTTP/1.1 545 ``` 546 547 #### Response 548 549 ```http 550 HTTP/1.1 200 OK 551 Content-Type: application/json 552 ``` 553 554 ```json 555 { 556 "Data": [ 557 { 558 "Object": "cipher", 559 "Id": "4c2869dd-0e1c-499f-b116-a824016df251", 560 "Type": 1, 561 "Favorite": false, 562 "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=", 563 "FolderId": null, 564 "OrganizationId": null, 565 "Notes": null, 566 "Login": { 567 "Uris": [ 568 { 569 "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=", 570 "Match": null 571 } 572 ] 573 }, 574 "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=", 575 "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=", 576 "Totp": null, 577 "Fields": null, 578 "Attachments": null, 579 "RevisionDate": "2017-11-07T22:12:22.235914Z", 580 "Edit": true, 581 "OrganizationUseTotp": false 582 } 583 ], 584 "Object": "list" 585 } 586 ``` 587 588 ### POST /bitwarden/api/ciphers 589 590 When a new item (login, secure note, etc.) is created on a device, it is sent 591 to the server with its fields encrypted via this route. 592 593 #### Request 594 595 ```http 596 POST /bitwarden/api/ciphers HTTP/1.1 597 Host: alice.example.com 598 Content-Type: application/json 599 ``` 600 601 ```json 602 { 603 "type": 1, 604 "favorite": false, 605 "name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=", 606 "folderId": null, 607 "organizationId": null, 608 "notes": null, 609 "login": { 610 "uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=", 611 "username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=", 612 "password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=", 613 "totp": null 614 } 615 } 616 ``` 617 618 #### Response 619 620 ```http 621 HTTP/1.1 200 OK 622 Content-Type: application/json 623 ``` 624 625 ```json 626 { 627 "Object": "cipher", 628 "Id": "4c2869dd-0e1c-499f-b116-a824016df251", 629 "Type": 1, 630 "Favorite": false, 631 "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=", 632 "FolderId": null, 633 "OrganizationId": null, 634 "Notes": null, 635 "Login": { 636 "Uris": [ 637 { 638 "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=", 639 "Match": null 640 } 641 ] 642 }, 643 "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=", 644 "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=", 645 "Totp": null, 646 "Fields": null, 647 "Attachments": null, 648 "RevisionDate": "2017-11-07T22:12:22.235914Z", 649 "Edit": true, 650 "OrganizationUseTotp": false 651 } 652 ``` 653 654 ### POST /bitwarden/api/ciphers/create 655 656 This route also allows to create a cipher, but this time, it is for a cipher 657 shared with an organization. 658 659 #### Request 660 661 ```http 662 POST /bitwarden/api/ciphers/create HTTP/1.1 663 Host: alice.example.com 664 Content-Type: application/json 665 ``` 666 667 ```json 668 { 669 "cipher": { 670 "type": 1, 671 "favorite": false, 672 "name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=", 673 "folderId": null, 674 "organizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79", 675 "notes": null, 676 "login": { 677 "uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=", 678 "username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=", 679 "password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=", 680 "totp": null 681 } 682 }, 683 "collectionIds": ["385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d"] 684 } 685 ``` 686 687 #### Response 688 689 ```http 690 HTTP/1.1 200 OK 691 Content-Type: application/json 692 ``` 693 694 ```json 695 { 696 "Object": "cipher", 697 "Id": "4c2869dd-0e1c-499f-b116-a824016df251", 698 "Type": 1, 699 "Favorite": false, 700 "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=", 701 "FolderId": null, 702 "OrganizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79", 703 "Notes": null, 704 "Login": { 705 "Uris": [ 706 { 707 "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=", 708 "Match": null 709 } 710 ] 711 }, 712 "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=", 713 "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=", 714 "Totp": null, 715 "Fields": null, 716 "Attachments": null, 717 "RevisionDate": "2017-11-07T22:12:22.235914Z", 718 "Edit": true, 719 "OrganizationUseTotp": false 720 } 721 ``` 722 723 ### GET /bitwarden/api/ciphers/:id and /bitwarden/api/ciphers/:id/details 724 725 #### Request 726 727 ```http 728 GET /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP/1.1 729 ``` 730 731 #### Response 732 733 ```http 734 HTTP/1.1 200 OK 735 Content-Type: application/json 736 ``` 737 738 ```json 739 { 740 "Object": "cipher", 741 "Id": "4c2869dd-0e1c-499f-b116-a824016df251", 742 "Type": 1, 743 "Favorite": false, 744 "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=", 745 "FolderId": null, 746 "OrganizationId": null, 747 "Notes": null, 748 "Login": { 749 "Uris": [ 750 { 751 "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=", 752 "Match": null 753 } 754 ] 755 }, 756 "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=", 757 "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=", 758 "Totp": null, 759 "Fields": null, 760 "Attachments": null, 761 "RevisionDate": "2017-11-07T22:12:22.235914Z", 762 "Edit": true, 763 "OrganizationUseTotp": false 764 } 765 ``` 766 767 ### PUT /bitwarden/api/ciphers/:id 768 769 This route is used to change a cipher. It can also be called via 770 `POST /bitwarden/api/ciphers/:id` (I think it is used by the web vault). 771 772 #### Request 773 774 ```http 775 PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP/1.1 776 Host: alice.example.com 777 Content-Type: application/json 778 ``` 779 780 ```json 781 { 782 "type": 2, 783 "favorite": true, 784 "name": "2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=", 785 "folderId": "14220912-d002-471d-a364-a82a010cb8f2", 786 "organizationId": null, 787 "notes": "2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=", 788 "secureNote": { 789 "type": 0 790 } 791 } 792 ``` 793 794 #### Response 795 796 ```http 797 HTTP/1.1 200 OK 798 Content-Type: application/json 799 ``` 800 801 ```json 802 { 803 "Object": "cipher", 804 "Id": "4c2869dd-0e1c-499f-b116-a824016df251", 805 "Type": 2, 806 "Favorite": true, 807 "Name": "2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=", 808 "FolderId": "14220912-d002-471d-a364-a82a010cb8f2", 809 "OrganizationId": null, 810 "Notes": "2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=", 811 "SecureNote": { 812 "Type": 0 813 }, 814 "Fields": null, 815 "Attachments": null, 816 "RevisionDate": "2017-11-07T22:12:22.235914Z", 817 "Edit": true, 818 "OrganizationUseTotp": false 819 } 820 ``` 821 822 ### POST /bitwarden/api/ciphers/:id/share 823 824 This route is used to share a cipher with an organization. The fields must be 825 encrypted with the organization key. 826 827 #### Request 828 829 ```http 830 POST /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/share HTTP/1.1 831 Host: alice.example.com 832 Content-Type: application/json 833 ``` 834 835 ```json 836 { 837 "cipher": { 838 "type": 2, 839 "favorite": true, 840 "name": "2.d00W2bB8LhE86LybnoPnEQ==|QqJqmzMMv2Cdm9wieUH66Q==|TV++tKNF0+4/axjAeRXMxAkTdRBuIsXnCuhOKE0ESh0=", 841 "organizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79", 842 "notes": "2.9m3XIbiJLk86thmF3UsO/A==|YC7plTgNQuMCkzYZC3iRjQ==|o8wZNQ3czr9sdeGXjOCalQwgPWsqOHZVnA2utZ+o/l4=", 843 "secureNote": { 844 "type": 0 845 } 846 }, 847 "collectionIds": ["385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d"] 848 } 849 ``` 850 851 #### Response 852 853 ```http 854 HTTP/1.1 200 OK 855 Content-Type: application/json 856 ``` 857 858 ```json 859 { 860 "Object": "cipher", 861 "Id": "4c2869dd-0e1c-499f-b116-a824016df251", 862 "Type": 2, 863 "Favorite": true, 864 "Name": "2.d00W2bB8LhE86LybnoPnEQ==|QqJqmzMMv2Cdm9wieUH66Q==|TV++tKNF0+4/axjAeRXMxAkTdRBuIsXnCuhOKE0ESh0=", 865 "OrganizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79", 866 "Notes": "2.9m3XIbiJLk86thmF3UsO/A==|YC7plTgNQuMCkzYZC3iRjQ==|o8wZNQ3czr9sdeGXjOCalQwgPWsqOHZVnA2utZ+o/l4=", 867 "SecureNote": { 868 "Type": 0 869 }, 870 "Fields": null, 871 "Attachments": null, 872 "RevisionDate": "2017-11-07T22:12:22.235914Z", 873 "Edit": true, 874 "OrganizationUseTotp": false 875 } 876 ``` 877 878 ### DELETE /bitwarden/api/ciphers/:id 879 880 This route is used to delete a cipher. It can also be called via 881 `POST /bitwarden/api/ciphers/:id/delete` (I think it is used by the web vault). 882 883 #### Request 884 885 ```http 886 DELETE /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP/1.1 887 Host: alice.example.com 888 ``` 889 890 #### Response 891 892 ```http 893 HTTP/1.1 200 OK 894 ``` 895 896 ### DELETE /bitwarden/api/ciphers 897 898 This route is used to delete ciphers in bulk. It can also be called via 899 `POST /bitwarden/api/ciphers/delete`. 900 901 #### Request 902 903 ```http 904 DELETE /bitwarden/api/ciphers HTTP/1.1 905 Host: alice.example.com 906 Content-Type: application/json 907 ``` 908 909 ```json 910 { 911 "ids": [ 912 "4c2869dd-0e1c-499f-b116-a824016df251", 913 "205c22f0-8642-0139-c874-543d7eb8149c" 914 ] 915 } 916 ``` 917 918 #### Response 919 920 ```http 921 HTTP/1.1 200 OK 922 ``` 923 924 ### PUT /bitwarden/api/ciphers/:id/delete 925 926 This route is used to soft delete a cipher, by adding a `deletedDate` 927 attribute on it. 928 929 #### Request 930 931 ```http 932 PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/delete HTTP/1.1 933 Host: alice.example.com 934 ``` 935 936 #### Response 937 938 ```http 939 HTTP/1.1 204 No Content 940 ``` 941 942 ### PUT /bitwarden/api/ciphers/delete 943 944 This route is used to soft delete ciphers in bulk. 945 946 #### Request 947 948 ```http 949 PUT /bitwarden/api/ciphers/delete HTTP/1.1 950 Host: alice.example.com 951 Content-Type: application/json 952 ``` 953 954 ```json 955 { 956 "ids": [ 957 "4c2869dd-0e1c-499f-b116-a824016df251", 958 "205c22f0-8642-0139-c874-543d7eb8149c" 959 ] 960 } 961 ``` 962 963 #### Response 964 965 ```http 966 HTTP/1.1 200 OK 967 ``` 968 969 ### PUT /bitwarden/api/ciphers/:id/restore 970 971 This route is used to restore a soft-deleted cipher, by removing the 972 `deletedDate` attribute. 973 974 #### Request 975 976 ```http 977 PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/restore HTTP/1.1 978 Host: alice.example.com 979 ``` 980 981 #### Response 982 983 ```http 984 HTTP/1.1 204 No Content 985 ``` 986 987 ### PUT /bitwarden/api/ciphers/restore 988 989 This route is used to restore ciphers in bulk. 990 991 #### Request 992 993 ```http 994 PUT /bitwarden/api/ciphers/restore HTTP/1.1 995 Host: alice.example.com 996 Content-Type: application/json 997 ``` 998 999 ```json 1000 { 1001 "ids": [ 1002 "4c2869dd-0e1c-499f-b116-a824016df251", 1003 "205c22f0-8642-0139-c874-543d7eb8149c" 1004 ] 1005 } 1006 ``` 1007 1008 #### Response 1009 1010 ```http 1011 HTTP/1.1 200 OK 1012 Content-Type: application/json 1013 ``` 1014 1015 ```json 1016 { 1017 "Data": [ 1018 { 1019 "Object": "cipher", 1020 "Id": "4c2869dd-0e1c-499f-b116-a824016df251", 1021 "Type": 1, 1022 "Favorite": false, 1023 "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=", 1024 "FolderId": null, 1025 "OrganizationId": null, 1026 "Notes": null, 1027 "Login": { 1028 "Uris": [ 1029 { 1030 "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=", 1031 "Match": null 1032 } 1033 ] 1034 }, 1035 "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=", 1036 "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=", 1037 "Totp": null, 1038 "Fields": null, 1039 "Attachments": null, 1040 "RevisionDate": "2021-04-23T12:58:01Z", 1041 "Edit": true, 1042 "OrganizationUseTotp": false 1043 }, 1044 { 1045 "Object": "cipher", 1046 "Id": "205c22f0-8642-0139-c874-543d7eb8149c", 1047 "Type": 2, 1048 "Favorite": true, 1049 "Name": "2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=", 1050 "FolderId": null, 1051 "OrganizationId": null, 1052 "Notes": "2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=", 1053 "RevisionDate": "2021-04-23T12:58:01Z", 1054 "Edit": true, 1055 "OrganizationUseTotp": false 1056 } 1057 ], 1058 "Object": "list" 1059 } 1060 ``` 1061 1062 1063 ### POST /bitwarden/api/ciphers/import 1064 1065 This route can be used to import several ciphers and folders in bulk. 1066 1067 In `folderRelationships`, the `key` is the index of the cipher in the `ciphers` 1068 list, and the `value` is the index of the folder in the `folders` list. 1069 1070 #### Request 1071 1072 ```http 1073 POST /bitwarden/api/ciphers/import HTTP/1.1 1074 Host: alice.example.com 1075 Content-Type: application/json 1076 ``` 1077 1078 ```json 1079 { 1080 "ciphers": [{ 1081 "type": 2, 1082 "favorite": true, 1083 "name": "2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=", 1084 "folderId": null, 1085 "organizationId": null, 1086 "notes": "2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=", 1087 "secureNote": { 1088 "type": 0 1089 } 1090 }, { 1091 "type": 1, 1092 "favorite": false, 1093 "name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=", 1094 "folderId": null, 1095 "organizationId": null, 1096 "notes": null, 1097 "login": { 1098 "uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=", 1099 "username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=", 1100 "password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=", 1101 "totp": null 1102 } 1103 }], 1104 "folders": [{ 1105 "name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=" 1106 }], 1107 "folderRelationships": [ 1108 {"key": 1, "value": 0} 1109 ] 1110 } 1111 ``` 1112 1113 #### Response 1114 1115 ```http 1116 HTTP/1.1 204 No Content 1117 ``` 1118 1119 ## Routes for folders 1120 1121 ### GET /bitwarden/api/folders 1122 1123 It retrieves the list of folders. 1124 1125 #### Request 1126 1127 ```http 1128 GET /bitwarden/api/folders HTTP/1.1 1129 ``` 1130 1131 #### Response 1132 1133 ```http 1134 HTTP/1.1 200 OK 1135 Content-Type: application/json 1136 ``` 1137 1138 ```json 1139 { 1140 "Data": [ 1141 { 1142 "Id": "14220912-d002-471d-a364-a82a010cb8f2", 1143 "Name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=", 1144 "RevisionDate": "2017-11-13T16:18:23.3078169Z", 1145 "Object": "folder" 1146 } 1147 ], 1148 "Object": "list" 1149 } 1150 ``` 1151 1152 ### POST /bitwarden/api/folders 1153 1154 It adds a new folder on the server. The name is encrypted on client-side. 1155 1156 #### Request 1157 1158 ```http 1159 POST /bitwarden/api/folders HTTP/1.1 1160 Host: alice.example.com 1161 Content-Type: application/json 1162 ``` 1163 1164 ```json 1165 { 1166 "name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=" 1167 } 1168 ``` 1169 1170 #### Response 1171 1172 ```http 1173 HTTP/1.1 200 OK 1174 Content-Type: application/json 1175 ``` 1176 1177 ```json 1178 { 1179 "Id": "14220912-d002-471d-a364-a82a010cb8f2", 1180 "Name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=", 1181 "RevisionDate": "2017-11-13T16:18:23.3078169Z", 1182 "Object": "folder" 1183 } 1184 ``` 1185 1186 ### GET /bitwarden/api/folders/:id 1187 1188 #### Request 1189 1190 ```http 1191 GET /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP/1.1 1192 ``` 1193 1194 #### Response 1195 1196 ```http 1197 HTTP/1.1 200 OK 1198 Content-Type: application/json 1199 ``` 1200 1201 ```json 1202 { 1203 "Id": "14220912-d002-471d-a364-a82a010cb8f2", 1204 "Name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=", 1205 "RevisionDate": "2017-11-13T16:18:23.3078169Z", 1206 "Object": "folder" 1207 } 1208 ``` 1209 1210 ### PUT /bitwarden/api/folders/:id 1211 1212 This route is used to rename a folder. It can also be called via 1213 `POST /bitwarden/api/folders/:id` (I think it is used by the web vault). 1214 1215 #### Request 1216 1217 ```http 1218 PUT /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP/1.1 1219 Host: alice.example.com 1220 Content-Type: application/json 1221 ``` 1222 1223 ```json 1224 { 1225 "name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=" 1226 } 1227 ``` 1228 1229 #### Response 1230 1231 ```http 1232 HTTP/1.1 200 OK 1233 Content-Type: application/json 1234 ``` 1235 1236 ```json 1237 { 1238 "Id": "14220912-d002-471d-a364-a82a010cb8f2", 1239 "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=", 1240 "RevisionDate": "2017-11-13T16:18:23.3078169Z", 1241 "Object": "folder" 1242 } 1243 ``` 1244 1245 ### DELETE /bitwarden/api/folders/:id 1246 1247 This route is used to delete a folder. It can also be called via 1248 `POST /bitwarden/api/folders/:id/delete` (I think it is used by the web vault). 1249 1250 #### Request 1251 1252 ```http 1253 DELETE /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP/1.1 1254 Host: alice.example.com 1255 ``` 1256 1257 #### Response 1258 1259 ```http 1260 HTTP/1.1 200 OK 1261 ``` 1262 1263 ## Organizations and Collections 1264 1265 ### GET /bitwarden/organizations/cozy 1266 1267 This route can be used to get information about the Cozy Organization. It 1268 requires a permission on the whole `com.bitwarden.organizations` doctype to 1269 access it. In particular, it gives the key to encrypt/decrypt the ciphers in 1270 this organization (encoded in base64). 1271 1272 #### Request 1273 1274 ```http 1275 GET /bitwarden/organizations/cozy HTTP/1.1 1276 Host: alice.example.com 1277 ``` 1278 1279 #### Response 1280 1281 ```http 1282 HTTP/1.1 200 OK 1283 Content-Type: application/json 1284 ``` 1285 1286 ```json 1287 { 1288 "organizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79", 1289 "collectionId": "385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d", 1290 "organizationKey": "oWeRYokoCMFsAja6lrp3RQ1PYOrex4tgAMECP4nX+a4IXdijbejQscvWqy9bMgLsX0HRc2igqBRMWdsPuFK0PQ==" 1291 } 1292 ``` 1293 1294 ### POST /bitwarden/api/organizations 1295 1296 This route can be used to create an organization, with a collection. 1297 1298 #### Request 1299 1300 ```http 1301 POST /bitwarden/api/organizations HTTP/1.1 1302 Host: alice.example.com 1303 Content-Type: application/json 1304 ``` 1305 1306 ```json 1307 { 1308 "name": "Family", 1309 "key": "4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=", 1310 "collectionName": "2.rrpSDDODsWZqL7EhLVsu/Q==|OSuh+MmmR89ppdb/A7KxBg==|kofpAocL2G4a3P1C2R1U+i9hWbhfKfsPKM6kfoyCg/M=" 1311 } 1312 ``` 1313 1314 #### Response 1315 1316 ```http 1317 HTTP/1.1 200 OK 1318 Content-Type: application/json 1319 ``` 1320 1321 ```json 1322 { 1323 "Id": "724db920-cc4b-0139-6ab2-543d7eb8149c", 1324 "Name": "Family", 1325 "Key": "4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=", 1326 "BillingEmail": "me@cozy.localhost", 1327 "Plan": "TeamsAnnually", 1328 "PlanType": 9, 1329 "Seats": 10, 1330 "MaxCollections": 1, 1331 "MaxStorageGb": 1, 1332 "SelfHost": true, 1333 "Use2fa": true, 1334 "UseDirectory": false, 1335 "UseEvents": false, 1336 "UseGroups": false, 1337 "UseTotp": true, 1338 "UseApi": false, 1339 "UsePolicies": false, 1340 "UseSSO": false, 1341 "UseResetPass": false, 1342 "HasPublicAndPrivateKeys": false, 1343 "ResetPasswordEnrolled": false, 1344 "UsersGetPremium": true, 1345 "Enabled": true, 1346 "Status": 2, 1347 "Type": 2, 1348 "Object": "profileOrganization" 1349 } 1350 ``` 1351 1352 ### GET /bitwarden/api/organizations/:id 1353 1354 This route can be used to fetch information about an organization. 1355 1356 #### Request 1357 1358 ```http 1359 GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c HTTP/1.1 1360 Host: alice.example.com 1361 ``` 1362 1363 #### Response 1364 1365 ```http 1366 HTTP/1.1 200 OK 1367 Content-Type: application/json 1368 ``` 1369 1370 ```json 1371 { 1372 "Id": "724db920-cc4b-0139-6ab2-543d7eb8149c", 1373 "Name": "Family", 1374 "Key": "4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=", 1375 "BillingEmail": "me@cozy.localhost", 1376 "Plan": "TeamsAnnually", 1377 "PlanType": 9, 1378 "Seats": 10, 1379 "MaxCollections": 1, 1380 "MaxStorageGb": 1, 1381 "SelfHost": true, 1382 "Use2fa": true, 1383 "UseDirectory": false, 1384 "UseEvents": false, 1385 "UseGroups": false, 1386 "UseTotp": true, 1387 "UseApi": false, 1388 "UsePolicies": false, 1389 "UseSSO": false, 1390 "UseResetPass": false, 1391 "HasPublicAndPrivateKeys": false, 1392 "ResetPasswordEnrolled": false, 1393 "UsersGetPremium": true, 1394 "Enabled": true, 1395 "Status": 2, 1396 "Type": 2, 1397 "Object": "profileOrganization" 1398 } 1399 ``` 1400 1401 ### GET /bitwarden/api/organizations/:id/collections 1402 1403 This route can be used to fetch information about the collections inside an 1404 organization. 1405 1406 #### Request 1407 1408 ```http 1409 GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/collections HTTP/1.1 1410 Host: alice.example.com 1411 ``` 1412 1413 #### Response 1414 1415 ```http 1416 HTTP/1.1 200 OK 1417 Content-Type: application/json 1418 ``` 1419 1420 ```json 1421 { 1422 "Data": [ 1423 { 1424 "Id": "62080a40-d75d-0139-21f1-543d7eb8149c", 1425 "OrganizationId": "724db920-cc4b-0139-6ab2-543d7eb8149c", 1426 "Name": "2.rrpSDDODsWZqL7EhLVsu/Q==|OSuh+MmmR89ppdb/A7KxBg==|kofpAocL2G4a3P1C2R1U+i9hWbhfKfsPKM6kfoyCg/M=", 1427 "Object": "collection" 1428 } 1429 ], 1430 "Object": "list" 1431 } 1432 ``` 1433 1434 ### DELETE /bitwarden/api/organizations/:id 1435 1436 This route can be used to delete an organization by its owner. 1437 1438 #### Request 1439 1440 ```http 1441 DELETE /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c HTTP/1.1 1442 Host: alice.example.com 1443 Content-Type: application/json 1444 ``` 1445 1446 ```json 1447 { 1448 "masterPasswordHash": "r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=" 1449 } 1450 ``` 1451 1452 #### Response 1453 1454 ```http 1455 HTTP/1.1 200 OK 1456 ``` 1457 1458 ### GET /bitwarden/api/organizations/:id/users 1459 1460 This route returns the list of users in the given organization. 1461 1462 #### Request 1463 1464 ```http 1465 GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/users HTTP/1.1 1466 Host: alice.example.com 1467 ``` 1468 1469 #### Response 1470 1471 ```http 1472 HTTP/1.1 200 OK 1473 Content-Type: application/json 1474 ``` 1475 1476 ```json 1477 { 1478 "Data": [ 1479 { 1480 "Object": "organizationUserUserDetails", 1481 "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601", 1482 "UserId": "0fbfc68d-ba11-416a-ac8a-a82600f0e601", 1483 "Type": 0, 1484 "Status": 2, 1485 "AccessAll": true, 1486 "Name": "Alice", 1487 "Email": "alice@example.com" 1488 }, 1489 { 1490 "Object": "organizationUserUserDetails", 1491 "Id": "89d99af0db1c0139605b543d7eb8149c", 1492 "UserId": "89d99af0db1c0139605b543d7eb8149c", 1493 "Type": 2, 1494 "Status": 1, 1495 "AccessAll": true, 1496 "Name": "Bob", 1497 "Email": "bob@example.com" 1498 } 1499 ], 1500 "Object": "list" 1501 } 1502 ``` 1503 1504 ### POST /bitwarden/api/organizations/:id/users/:user-id/confirm 1505 1506 This route is used by the owner of an organization to confirm that another user 1507 can use this sharing. The caller must check the fingerprint of the new member 1508 and encrypt the organization key with their public key. 1509 1510 #### Request 1511 1512 ```http 1513 POST /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/users/89d99af0db1c0139605b543d7eb8149c/confirm HTTP/1.1 1514 Host: alice.example.com 1515 Content-Type: application/json 1516 ``` 1517 1518 ```json 1519 { 1520 "key": "4.UT/TVY6qmAjNdax2WT9JcA97wSWvEudAlqpjfxrFUieOoGA88MxzbYjpCXajEST/PehD1I7KC93jwthng772extu+lLHSd/Ce+a5Qw8+pRxL7je8QgS8gmP0FhfRLc4bl5hUMTfQcUDiuiiNaDez6E9czOzk9iuVaGpEjK4YAYgQy25m3eGc+DTPv8206NJZ/lr8CpPyhwUHjtDhlOZnDWAf+a28x2EAj1ogZKKJGAUcRENitV8Joa7OGRO6dmxtTTnWOuPDk5DajGgzpIQURNuotVHcpBtCL8HzNAduQ9vtrPKJtyAsHRdjau2SwEnaLZmxAvp7d9VG3t5nDYtgWA==" 1521 } 1522 ``` 1523 1524 #### Response 1525 1526 ```http 1527 HTTP/1.1 200 OK 1528 ``` 1529 1530 ### GET /bitwarden/api/users/:id/public-key 1531 1532 This route gives the public key of a user. 1533 1534 #### Request 1535 1536 ```http 1537 GET /bitwarden/api/users/89d99af0db1c0139605b543d7eb8149c/public-key HTTP/1.1 1538 Host: alice.example.com 1539 ``` 1540 1541 #### Response 1542 1543 ```http 1544 HTTP/1.1 200 OK 1545 Content-Type: application/json 1546 ``` 1547 1548 ```json 1549 { 1550 "UserId": "89d99af0db1c0139605b543d7eb8149c", 1551 "PublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1LwbnLsT8w2OBPR/zy/zRQNH+jZzD6v4qUGAJg0NfoUkBSgtq9yjor2GgeRtdf8VuNTn1kcNrUIU4f9vE3ppNJgmUss4O29OP9/ATqtC/4ri4UCWTV0DPCF4gRU1SbgTg9O3yC2UYWmrs47SgU0wwT+f5AjfDC7GzhjyX68UYIIIeKSMZasjcy+wIPVAW0hYhcEoK3Coq2O1wVwM+b2fXPIMzn38onUTbMCrkVY+FzGg6NtZbKzPvVZ0iyfQ6BxvttqSViNPOpyz7gryDhgYKokV+kwj5ARDZWL6ml73U2lL7uapk5meNKZf8w7TJGepFiewGLm08VMht6lnIZBuDQIDAQAB" 1552 } 1553 ``` 1554 1555 ### DELETE /bitwarden/contacts/:id 1556 1557 This route can be used to refuse to give access to a user to shared ciphers. 1558 The contact will be deleted, and they will be revoked from all sharings. 1559 1560 #### Request 1561 1562 ```http 1563 GET /bitwarden/contacts/89d99af0db1c0139605b543d7eb8149c HTTP/1.1 1564 Host: alice.example.com 1565 ``` 1566 1567 #### Response 1568 1569 ```http 1570 HTTP/1.1 204 No-Content 1571 ``` 1572 1573 ## Icons 1574 1575 ### GET /bitwarden/icons/:domain/icon.png 1576 1577 This route returns an icon for the given domain, that can be used by the 1578 bitwarden clients. No authorization token is required. 1579 1580 If no favicon has been found for the domain, a fallback will be used, depending 1581 of the `fallback` parameter in the query-string: 1582 1583 - `default`: a default icon is returned 1584 - `404`: just a 404 - Not found error. 1585 1586 #### Request 1587 1588 ```http 1589 GET /bitwarden/icons/cozy.io/icon.png HTTP/1.1 1590 Host: alice.example.com 1591 ``` 1592 1593 ## Hub 1594 1595 The hub is a way to get notifications in real-time about cipher and folder 1596 changes. 1597 1598 ### POST /bitwarden/notifications/hub/negotiate 1599 1600 Before connecting to the hub, the client make a request to this endpoint to 1601 know what are the transports and formats supported by the server. 1602 1603 #### Request 1604 1605 ```http 1606 POST /bitwarden/notifications/hub/negotiate HTTP/1.1 1607 Host: alice.example.com 1608 ``` 1609 1610 #### Response 1611 1612 ```http 1613 HTTP/1.1 200 OK 1614 Content-Type: application/json 1615 ``` 1616 1617 ```json 1618 { 1619 "connectionId": "NzhhYjU4NjgtZTA1NC0xMWU5LWIzNzAtM2I1YzM3YWQyOTc1Cg", 1620 "availableTransports": [ 1621 { "Transport": "WebSockets", "Formats": ["Binary"] } 1622 ] 1623 } 1624 ``` 1625 1626 ### GET /bitwarden/notifications/hub 1627 1628 This endpoint is used for WebSockets to get the notifications in real-time. The 1629 client must do 3 things, in this order: 1630 1631 1. Make the HTTP request, with the token in the query string (`access_token`) 1632 2. Upgrade the connection to WebSockets 1633 3. Send JSON payload with `{"protocol": "messagepack", "version": 1}`.