Storing access tokens in Javascript and storing them in a native application have about equal protections - but by far most Javascript apps are left far more susceptible to third party code execution.
The answer is typically to make such credentials incapable of being exfiltrated by adding proof-of-possession, such as the use of MTLS or of the upcoming DPoP mechanism.
Note that preventing exfiltration doesn't prevent a third party from injecting logic to remote-drive use of those tokens and their access sans exfiltration.
While access tokens can be requested with specifically limited scopes of access, a backend server could potentially further control the level of access a front-end has. The problem is that the backend and frontend are typically defined in terms of business requirements. As such, there hasn't been a clear opportunity for standardizing such approaches.
When using a backend, my advice is to be sure you don't just have your API take a session cookie in lieu of an access token. API are typically not constructed with protections from XSRF and the like (or rather, an access token header serves as an XSRF protection while just a session cookie will not).
> Also, if I'm not mistaken, PKCE extension is optional in OAuth 2.0
Correct - although it is strongly recommended by best current practices, including recommending deployments limit/block access to clients which do not use PKCE.
> …and without it you cannot securely use the code flow (as you would have to expose the client secret).
PKCE has nothing to do with client secrets or client authentication. It provides additional strong correlation between the initial front-end request with the following code exchange request.
It was written to support native apps, as many such apps used the system browser for the authorization step and then redirected back into a custom URL scheme. Since custom URL scheme registrations are not regulated, malicious apps could attempt to catch these redirects. PKCE provides a verification that the same client software created both the redirect to the authorization endpoint and the request to the token endpoint. Even if a malicious piece of software got the code, they wouldn't have a way to exchange it for an access token.
Some of the original OAuth security requirements for clients have been found to be poorly implemented, but that PKCE provides equivalent protections against these particular issues. Unlike client-only implementation logic, PKCE support is something that an AS can audit. Hence it being likely that PKCE will be a requirement in future versions of OAuth.