I'm adapting the login function from this blogpost. The User struct (see below) has four fields, id, name, email and password. You can see a row from the database below. The fmt.Println
in the login function shows the user to be like this after the query to the database
&{3 testuser $2a$10$hS7sth8jIBN2/IXFTWBibu3Ko5BXm9zHO5AJZRAbAOQ04uv.Gs5Ym [116 101 115 116 117 115 101 114 64 103 109 97 105 108 46 99 111 109]}
In other words, it has the id
(3), the name
(testuser), the hashed password, but then also an array of numbers which surprised me a bit because it's not in the row from the database (see below). You'll also notice that the fmt.Println
is not displaying the email, even though that's visible in the row from the database, so there seems to be a problem here.
When bcrypt compares the hash and the password in the Login
function, it's giving me this error
hashedSecret too short to be a bcrypted password not auth
Can you explain why this error's being thrown?
func Login(password, email string) (u *User, err error) {
u = &User{}
err = db.QueryRow("select * from users where email=$1 ", email).Scan(&u.Id, &u.Name, &u.Password, &u.Email)
fmt.Println("u", u)
if err != nil {
fmt.Println("err", err)
}
err = bcrypt.CompareHashAndPassword(u.Password, []byte(password))
if err != nil {
u = nil
}
return
}
I have a user struct with the following fields
type User struct {
Id int
Name string
Email string
Password []byte
}
I created a table for it in postgres like this
CREATE TABLE "public"."users" (
"id" int4 NOT NULL DEFAULT nextval('users_id_seq'::regclass),
"username" varchar(255) NOT NULL COLLATE "default",
"email" varchar(255) NOT NULL COLLATE "default",
"password" bytea
)
WITH (OIDS=FALSE);
this is a row from the database
id | username | email | password
----+------------+----------------------+----------------------------------------------------------------------------------------------------------------------------
3 | testuser | testuser@gmail.com | \x24326124313024685337737468386a49424e322f495846545742696275334b6f3542586d397a484f35414a5a524162414f51303475762e477335596d
The array of numbers is the email address.
package main
import (
"fmt"
)
func main() {
email := []byte{116, 101, 115, 116, 117, 115, 101, 114, 64, 103, 109, 97, 105, 108, 46, 99, 111, 109}
fmt.Println(email)
fmt.Println(string(email))
}
Output:
[116 101 115 116 117 115 101 114 64 103 109 97 105 108 46 99 111 109]
testuser@gmail.com
After further study, I see you have select *
. Don't do that! You get items returned by the database, not necessarily what you want. Always be explicit in the fields you want returned and their order.
From the select *
, using the CREATE TABLE
definition, you likely got id
, username
, email
, and password
. From your Scan
, you set User
type Id
to id
, Name
to username
, Password
to email
, and Email
to password
. In other words, u.Password
contains email
(they have the same Go data type) and email
is too short to masquerade as a hashed password.
Match the fields in the select
and the Scan
, for example,
"select id, username, password, email from users where email=$1 "
Scan(&u.Id, &u.Name, &u.Password, &u.Email)