Skip to content

Commit ff39fe5

Browse files
committed
docs(developer): document app password scopes for app developers
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
1 parent e414900 commit ff39fe5

4 files changed

Lines changed: 150 additions & 0 deletions

File tree

‎developer_manual/basics/controllers.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,8 @@ To turn off checks the following *Attributes* can be added before the controller
879879
* ``#[NoTwoFactorRequired]``: A user can access the page before the two-factor challenge has been passed (use this wisely and only in two-factor auth apps, e.g. to allow setup during login)
880880
* ``#[NoCSRFRequired]``: Don't check the CSRF token (use this wisely since you might create a security hole; to understand what it does see :ref:`CSRF in the security section <csrf_introduction>`)
881881

882+
App passwords that a user limited to some parts of their account can't call any method by default, unless the user granted the whole app. To open single methods to them, see :doc:`../digging_deeper/app_password_scopes`.
883+
882884
.. note::
883885

884886
The attributes are only available in Nextcloud 27 or later. In older versions annotations with the same names exist:
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
===================
2+
App password scopes
3+
===================
4+
5+
.. versionadded:: 36
6+
7+
Since Nextcloud 36, users can limit an app password to some parts of their account,
8+
for example only Files or only Calendar. Each part is a *scope*, a string like
9+
``files:files:read``. Users pick them in *Settings > Security > Devices & sessions*
10+
by choosing *Custom* access.
11+
12+
A limited app password can't use your app's API or DAV collections until the user grants
13+
your whole app, or you add scopes to your controller methods. App passwords with full
14+
access and browser sessions work as before.
15+
16+
Closed by default
17+
-----------------
18+
19+
A limited app password can't reach:
20+
21+
* Controller methods without a scope attribute. They are refused with ``403`` (over OCS
22+
v1, in the OCS status of the response).
23+
* Pages. A ``TemplateResponse`` is refused, even if the method has a scope.
24+
* Admin-only methods, even when the user is an admin. A method counts as admin-only
25+
when it has none of ``#[NoAdminRequired]``, ``#[SubAdminRequired]`` and ``#[PublicPage]``.
26+
* Your app's DAV collections, see `Opening DAV collections`_.
27+
28+
Granting a whole app
29+
--------------------
30+
31+
Your app works with a limited app password without any changes, as long as the user
32+
limits it to your whole app. The app password then stores your app ID, like ``deck``,
33+
and can use your controller methods and DAV collections, with or without
34+
``#[TokenScope]``. Pages and admin-only methods stay closed.
35+
36+
Users can grant any app that is enabled for them, except apps that are reached through
37+
scopes, like Files, Calendar, Contacts, Tasks and Notifications.
38+
39+
Opening controller methods
40+
--------------------------
41+
42+
To open single methods instead, add ``#[TokenScope]`` to a controller class or method.
43+
A limited app password can then call the method if it holds that scope:
44+
45+
.. code-block:: php
46+
47+
<?php
48+
49+
declare(strict_types=1);
50+
51+
namespace OCA\MyApp\Controller;
52+
53+
use NCU\AppFramework\Http\Attribute\TokenScope;
54+
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
55+
use OCP\AppFramework\Http\DataResponse;
56+
use OCP\AppFramework\OCSController;
57+
58+
#[TokenScope(scope: 'myapp:notes:write')]
59+
class NotesController extends OCSController {
60+
#[NoAdminRequired]
61+
#[TokenScope(scope: 'myapp:notes:read')]
62+
public function list(): DataResponse {
63+
// Needs myapp:notes:read
64+
}
65+
66+
#[NoAdminRequired]
67+
public function create(string $text): DataResponse {
68+
// Needs myapp:notes:write from the class
69+
}
70+
}
71+
72+
The attribute on a method replaces the one on its class. It doesn't add to it.
73+
74+
It's safest to put the write scope on the class and the read scope on the read
75+
methods. A method added later then needs the write scope until you decide otherwise.
76+
77+
Users can't pick your own scopes in Settings yet, only your whole app. They become useful
78+
once clients can ask for scopes themselves.
79+
80+
.. note::
81+
82+
``TokenScope`` is in the ``NCU`` namespace, so it can still change until it moves to
83+
``OCP``. See :doc:`api`.
84+
85+
Naming scopes
86+
-------------
87+
88+
Name scopes ``<appid>:<resource>:<action>``, for example ``deck:boards:read``. The
89+
action is usually ``read`` or ``write``.
90+
91+
Apps that don't ship with Nextcloud can only use scopes that start with their own app
92+
ID. A method that asks for another app's scope is refused for every limited app
93+
password, even one that holds that scope.
94+
95+
Opening DAV collections
96+
-----------------------
97+
98+
DAV collections that an app registers in its ``info.xml`` belong to that app:
99+
100+
.. code-block:: xml
101+
102+
<sabre>
103+
<collections>
104+
<collection>OCA\MyApp\Sabre\RootCollection</collection>
105+
</collections>
106+
</sabre>
107+
108+
For the example app, a limited app password needs ``myapp:dav:read`` to read them
109+
(``GET``, ``HEAD``, ``OPTIONS``, ``PROPFIND``, ``REPORT``, ``SEARCH``) and
110+
``myapp:dav:write`` for everything else, or the whole app. Users can only grant the
111+
whole app in Settings so far.
112+
113+
Built-in scopes
114+
---------------
115+
116+
These are the scopes users can pick in Settings. Apps that don't ship with Nextcloud
117+
can't ask for them, but it helps to know what an app password may hold.
118+
119+
========================================== ==============================================
120+
Scope Gives access to
121+
========================================== ==============================================
122+
``files:files:read`` Reading through the Files and Sharing APIs, previews
123+
``files:files:write`` Changing files. Without it, all files are read-only
124+
``files:dav:read``, ``files:dav:write`` Files over WebDAV
125+
``files_sharing:shares:write`` Creating and changing shares
126+
``files_trashbin:dav:read``, ``…:write`` Deleted files over WebDAV
127+
``files_versions:dav:read``, ``…:write`` File versions over WebDAV
128+
``dav:calendar:read``, ``…:write`` Calendars over CalDAV and the calendar APIs
129+
``dav:contacts:read``, ``…:write`` Address books over CardDAV, contacts import
130+
``core:search:read`` Unified search
131+
``core:people:read`` Autocomplete, contacts menu, hovercards and profile fields
132+
``notifications:notifications:read`` Notifications and push
133+
========================================== ==============================================
134+
135+
Trying it out
136+
-------------
137+
138+
Create an app password with *Custom* access in Settings, tick your app, and call your API
139+
with it. Untick it again to check that your app refuses the app password.

‎developer_manual/digging_deeper/auth.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ Users & Authentication
1111
status
1212
out_of_office
1313
oidc
14+
app_password_scopes
1415
two-factor-provider

‎developer_manual/release_notes/new.rst‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ This pages covers new features of the platform.
1111
Every feature should just have a brief description. Details have to be documented on a dedicated, persistent page.
1212
After branch-off the contents below will be cleared.
1313
14+
App password scopes
15+
-------------------
16+
17+
Users can limit an app password to some parts of their account. A limited app password
18+
can only use your app if the user grants the whole app, or if you open single controller
19+
methods with ``#[TokenScope]`` (``NCU\AppFramework\Http\Attribute\TokenScope``).
20+
See :doc:`../digging_deeper/app_password_scopes`.
21+
1422
Email template blocks
1523
---------------------
1624

0 commit comments

Comments
 (0)