AFAIK, this is not totally accurate because the internet is a messy place. For example, the OAuth authorization code grant flow blesses passing the authorization code to the relying party (RP) in a GET request as a query parameter. The RP must protect against CSRF when receiving the authorization code.
Is this via PKCE or (ID) token nonce validation?
I don't get what you mean. Access-Control-Allow-Origin supports a wildcard. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ac...
per documentation, it's either "*" or "https://subdomain.somedomain.com"
Either way, kind of a digression into details of CORS that wasn't necessary for the introductory treatment, so I edited it out.
It should be clarified that by "currently authenticated session" it actually means cookies, which browsers are designed to automatically include in requests when they send a request to the same origin domain.
That's why CSRF attacks work: the attacker tricks the users' browser to send a request to a domain where the user was already authenticated, and that automatically inserts the user's session info in the request thus authorizing the request.
CSRF tokens work by adding a kind of API key that the browser somehow loads in a way that it is not stored as cookies. Servers then check for the CSRF token in each request to determine if the request is authorized. CSRF attacks alone don't work because they just forward cookies, and they do not include the CSRF token thus are rejected.
This is only true if you see CORS as a tool only to prevent reading data. I personally find it to be a useful tool to prevent writes, because the Origin header fulfils several of the purposes of a CSRF token. But that requires work on the backend to not actually perform writes unless the CORS parameters are valid. That sort of security is not the default (which is probably good)
I apologize for the length of the reply, I didn't have time to write a short one. But to sum up, CSRF is about writes, while CORS protects both reads and writes, and they're two very different things.
CSRF is a sort of "vulnerability", but really just a fact of the open web: that any site can create a form that POSTs any data to any other site. If you're on forum.evil.com and click the "reply" button (or anything at all), that could instead POST a transfer request to your.bank.com, and if you happen to be logged in, it'll happen with your currently authenticated session. When the bank implements CSRF protection, it ensures that a known token on the page (sometimes communicated through headers instead) is sent with the transfer. If that token isn't present, or doesn't match what's expected, reject the request. It ensures that only forms generated by bank.com will have any effect, and it works because evil.com can't use JS to read the content of the page from bank.com due to cross-origin restrictions.
CORS on the other hand is an escape hatch from a different cross-origin security mechanism that browsers enable by default: that a script on foo.com cannot make requests to bar.com except for "simple" requests (the definition of which is anything but simple; just assume any request that can do anything interesting is blocked). CORS is a way for bar.com to declare with a header that foo.com is in fact allowed to make such requests, and to drop the normal cross-origin blocking that would occur otherwise. You only have to use CORS to remove restrictions: if you do nothing, maximum security is the default. It's also strictly a browser technology: non-browser user agents do not need or use CORS and can call any API anytime.
Fun fact: you don't need CSRF protection at all if your API is strictly JSON-based, or uses any content type that isn't one of the built-in form enclosure types. The Powers That Be are talking about adding a json enclosure type to forms, but submitting it would be subject to cross-origin restrictions, same as it is with JS.