The way you can handle auth callback is on the frontend (since that's where the state should be stored). Essentially, you want to create a frontend route which the provider can send the user to.
In that route, you want to extract the code from the query param and also the state. You then want to check if the state stored on the frontend is the same and if not reject.
If the state is the same, then you want to call the backend's signinup API (exposed via the backend sdk) with the auth code. This will exchange the auth code with the provider and create the user in supertokens. From there on, you can override the signinup API on the backend to create a JWT and send that to the frontend.
If you want to redirect the user to the backend and not the frontend, you will have to somehow store the state on the backend.. and then call the signinup API post state verification (similar to how the frontend would have called it). Alternatively, you could redirect the user from the backend to the frontend with the auth code and state and continue the frontend flow as mentioned above.
These things would have been simpler if you were using our frontend SDK somehow..