You should not pass the actual authentication token (jwt) in the url for multiple reasons. Sensitive data should never appear in urls.
Passing a one-time token to be exchanged for the authentication token is somewhat more secure, but you either can make it purely stateless or one-time, but not both, because you will have to remember used tokens. That's fine, just something to consider. Also if you can pass it in the request body or header, you should (eg. a post request would have it in the body instead of the url).
However, if you are doing this, you are reinventing single sign-on. What you need is already available in multiple different forms, most notably OIDC and SAML. In a more best-practice-like architecture, you would have a login endpoint that would act as the authentication provider (say an OIDC provider). That would issue auth tokens that consumers (relying parties in OIDC terms, these are basically your apps) could consume either directly or make their own sessions based on the tokens received from the identity provider.
In case of the authorization code flow, it would look something like
- user visits app1, but is not logged in (does not have valid tokens or a session)
- user gets redirected to the login server, where he logs in and is redirected back to the app1 with an auth code
- app1 in the background could exchange the code for tokens that you could use on your backend to impersonate the user, so every backend component can make sure who the user was, and also in this step app1 can create a plain old session for the user if it wants
- in subsequent requests, the user would already have the session (or an id token)
- when the user visits app2, depending on what exact flow you choose, the client would either have an id token already that it could send to app2, or would be redirected to the login server, but there the user would be logged in already, so it would all be transparent from a user's perspective and app2 would just work.
A major benefit of the above is it's a standard approach, there are well-tested flows and ready-made components that you can use and with which you can achieve a reasonable assurance that they are secure. Another benefit is that all components are replacable, you can switch to another identity provider relatively easily (you can choose from many, including open source options, or very cheap hosted ones), and relying parties (apps) will also be easy and standard to make.