netlify / gotrue-js

JavaScript client library for GoTrue
MIT License
471 stars 68 forks source link

accept pre-hashed passwords #114

Open fool opened 4 years ago

fool commented 4 years ago

All methods that can use a password, essentially require it to be sent in plaintext (yes, over https, but still not encoded in any way):

It would be great if there were some more secure method of passing this password around during user creation/login/update

fool commented 4 years ago
mraerino commented 4 years ago

i have not seen this implemented a lot in other services. there are several pitfalls here.

for one, the backend should be able to upgrade the hashing method to provide more security without the frontend being affected by that (breaking change otherwise)

also, the reason we store passwords hashed in a DB is so that a DB leak will not allow the attacker to use the credentials. if we allowed login using hashes, leaked DBs could be used for login. I don't think it's considered good practice to do hashing in the browser for login. therefore the proposed method is not necessarily more secure.

The customer stated several reason for wanting this feature:

erezrokah commented 4 years ago

I think the suggestion is to hash both on the client side and again on the server side.

Sending a client side hash of the password does not provide additional security when intercepted since one could simply use the intercepted hash for login (doesn't really need the original password).

It does help if the same password is used for other services, and those services don't use the same hash function, so the hash will only be valid for gotrue.

Another reason I've seen clients use this method is for preventing password managers from saving passwords, but not sure this is valid for this library.

erezrokah commented 4 years ago

On a side note, a simple workaround would be to hash the password before calling any of those methods.

johndpope commented 1 year ago

a diffferent context - but related I'm running some node code - I have a valid apple session from a mobile client I want to setup some node code on ec2 server to host this https://github.com/johndpope/Sign-in-with-Apple-for-supabase

I want to find matching users on system and give a jwt back. If I can instantiate a user by id - it would be preferable - but all this code in repo seems specific to client side browser stuff. I have db access to auth.users via postgres node. This is all server side - admin credentials.

apple gives me this


    const jwtClaims = { iss: 'https://appleid.apple.com',
        aud: 'app.test.ios', 
        exp: 1579483805,
        iat: 1579483205,
        sub: '000317.c7d501c4f43c4a40ac3f79e122336fcf.0952',
        at_hash: 'G413OYB2Ai7UY5GtiuG68A',
        email: 'da6evzzywz@privaterelay.appleid.com',
        email_verified: 'true',
        is_private_email: 'true',
        auth_time: 1579483204 }

I find matching email email: 'da6evzzywz@privaterelay.appleid.com',

const res = await db.query('SELECT id,email,encrypted_password FROM auth.users WHERE email = $1', ["test@test.com"]);
    console.log("ok:",res.rows[0]);
    if (res.rows.length == 0){
        return null;
    }

    auth
    .login(res.rows[0].email, res.rows[0].encrypted_password, true)
    .then(response => {
        console.log("response:",response);
        return response;
    })

user.jwt() // would work - how can I instantiate an appropriate user? how can I give back a valid JWT? (I'm also wanting to create the user - but that's a separate problem)

UPDATE it doesn't look like anyone ever created the access_token via javascript I could convert apple code https://github.com/netlify/gotrue/blob/master/api/token.go#L166

func generateAccessToken(user *models.User, expiresIn time.Duration, secret string) (string, error) {
    claims := &GoTrueClaims{
        StandardClaims: jwt.StandardClaims{
            Subject:   user.ID.String(),
            Audience:  user.Aud,
            ExpiresAt: time.Now().Add(expiresIn).Unix(),
        },
        Email:        user.Email,
        AppMetaData:  user.AppMetaData,
        UserMetaData: user.UserMetaData,
    }

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString([]byte(secret))
}

tokenString, terr = generateAccessToken(user, time.Second*time.Duration(config.JWT.Exp), config.JWT.Secret)

UPDATE I ported over the code - though not entirely tested.... https://github.com/johndpope/Sign-in-with-Apple-for-supabase/blob/master/server.js#L172

UPDATE 2 - I can create a user with admin - but now I want to issue a corresponding jwt. Is there a way?


const { data: newUser, error } = await supabase.auth.admin.createUser({
            email: jwtClaims.email,
            email_confirm: true, // missing provide / identities guff
            user_metadata:jwtClaims
        })
        console.log("newUser:", newUser);
        console.log("jwt:", newUser.jwt());

andledPromiseRejectionWarning: TypeError: newUser.jwt is not a function
    at returnExistingSupabaseJWTorCreateAccount (/Users/johndpope/Documents/gitWorkspace/Sign-in-with-Apple-for-node/server.js:189:31)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
(Use `node --trace-warnings ...` to show where the warning was created)

    // create an access token
        let claims = {
            "StandardClaims": {
                "sub": newUser.id,
                "aud": "",
                "exp": Math.floor(Date.now() / 1000),
            },
            "Email": newUser.Email,
            "AppMetaData": newUser.AppMetaData,
            "UserMetaData": newUser.UserMetaData,
        }
        console.log("✅ claims:", claims);
        const jwt = sign(claims, config.supabase.jwtSecret);