Edit: After posting this I realized it's almost the exact same answer given by Ali.S (slightly different but the overall approach is the same.) It started out as something completely different though.
This method assumes that all communications are being held over a series of secure tunnels. How you achieve this doesn't matter. I would suggest TLS, but that's just me.
- Client => Game Server The client connects to the game server and initiates a login session.
- Game Server => Auth Server The game server connects to the auth server and requests a session ID token from the auth server. This connection is kept open to listen for the login success/failure.
- Game Server => Client The session ID token is sent back to the client.
- Client => Auth Server The client sends the session ID to the auth server along with the username and password of the user, and some information about the server (IP, TLS public key, etc. See footnotes)
- Auth Server => Game Server The auth server then sends information about the login to the game server (success state, username, stats, etc) using the session ID provided by the client.
- Game Server => Client The game server tells the client that the auth was successful, and lets them in.
- All connections except for the initial client to game server connection are now torn down.
Alternatively, you can give the game servers a dedicated port to listen for logins. If you choose this route, then the flow would look like this:
- Client => Auth Server The client sends the username, password, and server IP to the auth server.
- Auth Server => Game Server + Client If the login is successful, the auth server sends a unique token to the game server and client. Send the IP of the client to the game server too, so that the token can't be stolen.
- Client => Game Server The client then sends the token to the game server, where it is then verified and deleted on the game server. The game server then lets the client in.
This second approach would make the overall implementation a bit easier.
The reason I specify that some information should be sent about the game server to the auth server is to harden the process against spoofs. The server can verify the information to make sure that it is authorizing the connection that the player expects.
Session IDs would not have to be cryptographically secure, though it would make spoofing connections somewhat harder if they were.
If you do choose to go the TLS route, you can set up a signing server that signs all the certs used by your infrastructure, and add it as a trusted CA in the client/server software. So long as you don't let your signing cert get loose, you'll be able to provide some decent authentication.
For the sake of mitigating DoS attacks, make connections timeout after 20 or fewer seconds. If it lasts longer than that, then something is wrong and you don't need to wait 3 minutes waiting for the connection to timeout on its own.