Solid way to handle user login with cookies?

Hello all, this code is working and I’m happy with it’s functionality, but I don’t know if there’s something from a security perspective I’m missing. I believe the code is ok, but you never know.

What I’m doing it taking the user information and storing it in PostgrSQL. I also want to set a cookie which is working, but clearly I don’t want to set anything sensitive in plane text. I also don’t want to store the users hashed password in the cookie, so I create a “token”, which is a mix of things, and store that in the database. The token is updated when the cookies time out, and I check the value of the token in the cookie vs what’s stored in the database. This occurs for every page the user visits.

It seems like a lot of overhead, but it’s working and “seems” secure.

Thoughts?

const passwordSalt = "MySecretSalt"
//UserLogin will handle user authentication
func UserLogin(email string, password string) bool {

	result := &User{}

	email = email
	password = password

	hasher := sha512.New()
	hasher.Write([]byte(passwordSalt))
	hasher.Write([]byte(email))
	hasher.Write([]byte(password))

	hashedPassword := base64.URLEncoding.EncodeToString(hasher.Sum(nil))

	row := db.QueryRow(`SELECT email, password, authtoken FROM golang.users WHERE email=$1 AND password=$2`, email, hashedPassword)
	err := row.Scan(&result.Email, &result.Password, &result.authtoken)

	//println("model userauth - Printing authtoken: " + storedauthtoken)

	if err != nil {
		println("model userauth - Invalid User Authentication")
		return false
	} else {
		println("model userauth - Valid User Authentication")
		return true
	}
}

//UpdateToken sets the auth token in the cookie and in the database
func UpdateToken(w http.ResponseWriter, r *http.Request) {

	firstname := strings.Trim(r.FormValue("firstname"), " ")
	lastname := strings.Trim(r.FormValue("lastname"), " ")
	email := strings.Trim(r.FormValue("email"), " ")

	fullname := firstname + " " + lastname

	now := time.Now()
	hasher := sha512.New()
	randomer := now.Weekday().String()

	hasher.Write([]byte(passwordSalt))
	hasher.Write([]byte(email))
	hasher.Write([]byte(randomer))

	cookieToken := base64.URLEncoding.EncodeToString(hasher.Sum(nil))

	expiration := time.Now().Add(7 * 24 * time.Hour)
	tokenCookie := http.Cookie{Name: "authValue", Value: cookieToken, Expires: expiration}
	emailCookie := http.Cookie{Name: "emailValue", Value: email, Expires: expiration}
	nameCookie := http.Cookie{Name: "nameValue", Value: fullname, Expires: expiration}
	http.SetCookie(w, &tokenCookie)
	http.SetCookie(w, &emailCookie)
	http.SetCookie(w, &nameCookie)

	_, err := db.Exec(`UPDATE golang.users SET authtoken = $1 WHERE email = $2`, cookieToken, email)

	if err != nil {
		println("model userauth - Failed to Update SQL authtoken")
		//return false
	} else {
		println("model userauth - Updated SQL authtoken")
		//return true
	}

}

Did you consider to use an existing solution like JSON Web Tokens? JWTs are encrypted tokens than can be validated without access to a persistence system like a database. Take a look!

Of course you will have to set and read a JWT to and from a HTTP cookie, but that is the easy part.

1 Like

Thank you, I wasn’t aware of them. I’m new to Go programming, I’ll take a look and see if I can use those.