In general, we try to avoid putting credentials in URLs, because URLs leak places (such as server or proxy logs, browser history, etc.). In some cases, such as OAuth, people have decided that the simplicity of a redirected GET request is worth the risk of putting a credential (the authorization code) in the URL. However, in such cases, the credential really needs to be both short-lived and single-use.
The latter requirement is a problem for JWTs, as there is no way to revoke them; they are valid until they expire, whether that's in seconds or centuries (or until their signature verification key is rotated out). That prevents making them single-use. You could get away with using a JWT instead of a random token, but if so, you should do your best to keep it out of the URL (e.g. send it in a POST request body instead). You can use an automatically-submitting HTML form to do this, for example. The JWT lifetime should also be VERY short, possibly as little as a single-digit number of seconds (most of the time it will be used within a second or two, but sometimes people have very high-latency connections - e.g. over multiple satellite hops - or unreliable connections or overloaded servers, in which case it might take a few seconds to get through).
Note that the secrecy of the authorization code is EXTREMELY important. OAuth2 contains mitigations for some other weaknesses, such as requiring that the redirect URL matches a short list of pre-registered options (mitigates leaking the client secret or even not having one, as in PKCE), or the State parameter (mitigates CSRF even if the server doesn't notice that the user in question never tried to start an OAuth flow). However, if the authorization code is stolen (or is a JWT or similar but can be tampered with) while still valid, then any attacker who is able to perform an OAuth flow themselves can authorize themselves access to the victim's account, by swapping out or modifying the returned authorization code.