This document explains the login process for the FirstClass protocol. This only covers logging in with a user ID and password (or saved password digest). However, there are other methods of logging in (such as using a login ticket, or SSO if that's set up) that are not covered here.
To log in, you will need to calculate a user's login digest. This is a SHA512 hash of the user ID (in UPPERCASE) and their password. For example, the login digest for the user jsmith with password Password123 would be 1d5673f40e1efffa2e523edefbef1c09727de453a4b22d0a58c6c8415090eddad5b6485a09fa77170732a98c457d3f3df840c78c8545fe73ab1c4a1484f2b357. Notice how the hexadecimal representation is the actual digest. You aren't using the result of the hash directly, you're using the ASCII representation of the hash. Also, if you want to save a user's password so they don't have to re-enter it later, you can securely store the login digest instead of their plaintext password.
After the initial cConnReq and sConnReq packets are exchanged, the server will set the fcpMD5Challenge field of the AUTHENTICATEOBJID object. This is done to protect against replay attacks. You must calculate an auth digest by computing an HMAC hash with SHA512, an input of the challenge given to you by the server, and the key set to the login digest you calculated earlier.
Once you've done that, you can finally begin the login process. First, you must set three fields on the AUTHENTICATEOBJID object. fcpLoginConnAddress should be set to an fdString containing the public IP address of the client. (not actually sure if this is required) fcpLoginOptions should be set to the fdShort fcpLoginOptSavedPWNotify. Finally, fcpLoginDigest should be set to an fdBinary containg the auth digest you calculated earlier. (never send the user's plaintext password or login digest over FCP!)
After these three fields are set, you can finally send a cLogin packet. The fields of this packet should be set to their defaults with the exception of the UserIDLength, and UserID fields, which should be set to the user ID you're logging in as.
The server will respond to your cLogin with an sLogin packet. If you've logged in successfully, this packet will have a return code of 0 and the server will immediately start setting fields on the SESSIONDATAOBJID object with information about the user account. If the login failed, the return code will be non-zero, corresponding to the appropriate error code. (a common error code is 1003, meaning the user ID or password was incorrect)