Authentication
Security decides which caller may perform an operation. This chapter explains how a client becomes that caller: as a frontend user, a backend user, or a script holding a key.
tca_api does not log anyone in itself. It reads the identity that TYPO3 or an installed extension established for the request.
How tca_api sees identity
Before any access check, tca_api resolves the caller of the request, the principal, through a chain of authenticators:
| Authenticator | Identity |
|---|---|
| API keys | A key sent as X- or Authorization: Bearer. Only registered
when the api_key
extension is installed, see Scripts and machine-to-machine. |
| Session | The frontend user and the backend user that TYPO3 restored from their
session cookies (fe_, be_). Always active. |
| Custom | Any Authenticator of another extension, see
Authenticators. |
Credentials sent with the request are checked before the session. A request
without any credentials is anonymous and can only reach PUBLIC operations.
The two error codes mean different things:
| Status | Meaning |
|---|---|
401 Unauthorized | Credentials were sent, but they are invalid: a wrong, expired or
revoked key, or a key used from a forbidden IP address or site. The
WWW- header names the scheme. The request is rejected
even if a valid session exists. |
403 Forbidden | The caller is anonymous, or authenticated but not allowed: the role does not match, the record belongs to another user, or the key's scopes do not cover the operation. |
Note
An anonymous request to a protected operation answers 403, not
401. 401 always means "your credentials are wrong", so a client can
tell a broken key from a missing permission.
Browser and single-page apps
In the browser the regular TYPO3 login is the authentication. A user who
logged in through felogin
holds a frontend session cookie, and every API request that carries the cookie
acts as that user. A backend editor who is logged in to the TYPO3 backend in
the same browser also carries the backend session cookie and satisfies
BE_, and BE_ for administrators.
On the same origin nothing has to be configured: fetch sends the cookies
of the own origin by default.
Cross-origin clients
A single-page app on another origin needs three things:
-
Allow credentials and name the app's origin in the site settings:
config/sites/<site>/settings.yamltca_api: corsEnabled: true corsOrigin: 'https://app.example.com' corsAllowCredentials: trueCopied!Warning
With
corsandOrigin: '*' corsenabled, tca_api echoes the request'sAllow Credentials Originback. Any website can then read the API on behalf of a logged-in visitor. Always name the origin. -
Send the cookies with every request:
const response = await fetch('https://www.example.com/_api/articles', { credentials: 'include', });Copied! -
Make sure the browser sends the cookie at all. The frontend session cookie defaults to
Same, which browsers only send to the same site (Site=Lax app.andexample. com www.are the same site). For an app on a different domain, the cookie must beexample. com Same, which requires HTTPS:Site=None config/system/additional.php$GLOBALS['TYPO3_CONF_VARS']['FE']['cookieSameSite'] = 'none';Copied!This affects every frontend session of the installation, so prefer hosting the app on a subdomain of the site.
Logging in from a script
Logging in a frontend user programmatically, e.g. with curl, is impractical.
Since TYPO3 v13 every frontend login has to carry a signed request token
(__) that is bound to a nonce cookie. A script would first
have to load a page with the felogin form, extract the token, keep the cookie
jar and then post the credentials. For scripts and server-to-server calls use
API keys instead.
Scripts and machine-to-machine
The api_key extension (documentation) adds stateless API keys. tca_api suggests it but does not require it; once it is installed, tca_api picks it up automatically.
composer require maikschneider/api-key
Create a key on the command line. The key is printed once and cannot be recovered:
# Service key: no user, satisfies AccessRole::API_KEY
vendor/bin/typo3 apikey:create --title="CI deploy" --scope=articles:write --expires="+90 days"
# Acts as frontend user 12, with its groups
vendor/bin/typo3 apikey:create --title="Partner import" --fe-user=12
# Acts as backend user 3
vendor/bin/typo3 apikey:create --title="Editorial sync" --be-user=3
Send it in either header:
curl -H "X-API-Key: ${TYPO3_API_KEY}" https://example.com/_api/articles
curl -H "Authorization: Bearer ${TYPO3_API_KEY}" https://example.com/_api/articles
What a key may do depends on what it is bound to:
| Key | Satisfies |
|---|---|
| Service key | API_ |
| Bound to a frontend user | FE_, FE_, OWNER and API_ |
| Bound to a backend user | BE_, BE_ (for admins) and API_ |
The key's scopes always restrict it, also for a key bound to a user, see Scopes. A key without scopes is unrestricted, so give every key the narrowest scopes it needs.
Keyed requests are stateless: they create no fe_ row, send no
Set- and leave lastlogin untouched.
Tip
Behind Apache, the Authorization header only reaches PHP with
CGIPass. The X- header always works.
How the bridge maps keys to principals, adds X- to the CORS
headers and documents the security schemes is described in
API keys.
Other extensions
Extensions that log a user in through TYPO3's authentication services work as well, because tca_api reads the resulting session:
| Extension | Notes |
|---|---|
| kuhschnappel/authtoken | Tokens for frontend users, sent in an X- header. Supports
TYPO3 up to v13.4. It relies on FE_, so every
cookie-less request creates an fe_ row and sends
Set-. |
| r3h6/oauth2-server | An OAuth2 server for frontend users. Supports TYPO3 up to v13.4. |
Attention
in2frontendauthentication
does not satisfy FE_ or FE_. It adds frontend groups
for matching IP addresses but never logs in a user record, so the request
stays without a frontend user.
Session-based extensions that only log in backend users, such as OAuth2 or OpenID Connect login providers for the backend, apply to browsers, not to scripts: the frontend only restores a backend user when the backend session cookie is present.
Swagger UI
Swagger UI at {api offers the authentication schemes of
the OpenAPI document in its Authorize dialog:
- Sessions (
Frontend,Session Backend): log in on the website or in the backend in the same browser and reload Swagger UI. The browser sends the session cookie by itself.Session - API keys (
Api,Key Api): click Authorize and paste a key. The key is kept across reloads until you click Logout.Key Bearer