Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions developer_manual/basics/controllers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,8 @@ To turn off checks the following *Attributes* can be added before the controller
* ``#[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)
* ``#[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>`)

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`.

.. note::

The attributes are only available in Nextcloud 27 or later. In older versions annotations with the same names exist:
Expand Down
140 changes: 140 additions & 0 deletions developer_manual/digging_deeper/app_password_scopes.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
===================
App password scopes
===================

.. versionadded:: 36

Since Nextcloud 36, users can limit an app password to some parts of their account,
for example only Files or only Calendar. Each part is a *scope*, a string like
``files:files:read``. Users pick them in *Settings > Security > Devices & sessions*
by choosing *Custom* access.

A limited app password can't use your app's API or DAV collections until the user grants
your whole app, or you add scopes to your controller methods. App passwords with full
access and browser sessions work as before.

Closed by default
-----------------

A limited app password can't reach:

* Controller methods without a scope attribute. They are refused with ``403`` (over OCS
v1, in the OCS status of the response).
* Pages. A ``TemplateResponse`` is refused, even if the method has a scope.
* Admin-only methods, even when the user is an admin. A method counts as admin-only
when it has none of ``#[NoAdminRequired]``, ``#[SubAdminRequired]`` and ``#[PublicPage]``.
* Your app's DAV collections, see `Opening DAV collections`_.

Granting a whole app
--------------------

If your app has an entry in the app menu, it works with a limited app password without
any changes, as long as the user limits it to your whole app. The app password then
stores your app ID, like ``deck``, and can use your controller methods and DAV
collections, with or without ``#[TokenScope]``. Pages and admin-only methods stay closed.

Apps without an app menu entry can't be granted this way, so users can't open them to
limited app passwords from Settings yet. Files, Calendar, Contacts and Tasks have scopes
of their own and can't be granted as a whole either, and neither can Assistant.

Opening controller methods
--------------------------

To open single methods instead, add ``#[TokenScope]`` to a controller class or method.
A limited app password can then call the method if it holds that scope:

.. code-block:: php

<?php

declare(strict_types=1);

namespace OCA\MyApp\Controller;

use NCU\AppFramework\Http\Attribute\TokenScope;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;

#[TokenScope(scope: 'myapp:notes:write')]
class NotesController extends OCSController {
#[NoAdminRequired]
#[TokenScope(scope: 'myapp:notes:read')]
public function list(): DataResponse {
// Needs myapp:notes:read
}

#[NoAdminRequired]
public function create(string $text): DataResponse {
// Needs myapp:notes:write from the class
}
}

The attribute on a method replaces the one on its class. It doesn't add to it.

It's safest to put the write scope on the class and the read scope on the read
methods. A method added later then needs the write scope until you decide otherwise.

Users can't pick your own scopes in Settings yet, only your whole app. They become useful
once clients can ask for scopes themselves.

.. note::

``TokenScope`` is in the ``NCU`` namespace, so it can still change until it moves to
``OCP``. See :doc:`api`.

Naming scopes
-------------

Name scopes ``<appid>:<resource>:<action>``, for example ``deck:boards:read``. The
action is usually ``read`` or ``write``.

Apps that don't ship with Nextcloud can only use scopes that start with their own app
ID. A method that asks for another app's scope is refused for every limited app
password, even one that holds that scope.

Opening DAV collections
-----------------------

DAV collections that an app registers in its ``info.xml`` belong to that app:

.. code-block:: xml

<sabre>
<collections>
<collection>OCA\MyApp\Sabre\RootCollection</collection>
</collections>
</sabre>

For the example app, a limited app password needs ``myapp:dav:read`` to read them
(``GET``, ``HEAD``, ``OPTIONS``, ``PROPFIND``, ``REPORT``, ``SEARCH``) and
``myapp:dav:write`` for everything else, or the whole app. Users can only grant the
whole app in Settings so far.

Built-in scopes
---------------

These are the scopes users can pick in Settings. Apps that don't ship with Nextcloud
can't ask for them, but it helps to know what an app password may hold.

========================================== ==============================================
Scope Gives access to
========================================== ==============================================
``files:files:read`` Reading through the Files and Sharing APIs, previews
``files:files:write`` Changing files. Without it, all files are read-only
``files:dav:read``, ``files:dav:write`` Files over WebDAV
``files_sharing:shares:write`` Creating and changing shares
``files_trashbin:dav:read``, ``…:write`` Deleted files over WebDAV
``files_versions:dav:read``, ``…:write`` File versions over WebDAV
``dav:calendar:read``, ``…:write`` Calendars over CalDAV, upcoming events, calendar import and export, out of office
``dav:contacts:read``, ``…:write`` Address books over CardDAV, contacts import
``core:search:read`` Unified search
``core:people:read`` Autocomplete, contacts menu, hovercards and profile fields
``notifications:notifications:read`` Notifications and push
========================================== ==============================================

Trying it out
-------------

Create an app password with *Custom* access in Settings, tick your app, and call your API
with it. Untick it again to check that your app refuses the app password.
1 change: 1 addition & 0 deletions developer_manual/digging_deeper/auth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ Users & Authentication
status
out_of_office
oidc
app_password_scopes
two-factor-provider
8 changes: 8 additions & 0 deletions developer_manual/release_notes/new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ This pages covers new features of the platform.
Every feature should just have a brief description. Details have to be documented on a dedicated, persistent page.
After branch-off the contents below will be cleared.

App password scopes
-------------------

Users can limit an app password to some parts of their account. A limited app password
can only use your app if the user grants the whole app, or if you open single controller
methods with ``#[TokenScope]`` (``NCU\AppFramework\Http\Attribute\TokenScope``).
See :doc:`../digging_deeper/app_password_scopes`.

Email template blocks
---------------------

Expand Down
Loading