I’m making a webapp which encrypts each user’s data, using AES-256, with a unique key for each account. I’m thinking about adding external signon via the “Sign in with Google” scheme. However, I’ve done some digging, and I’m not sure if it’s possible in my situation.
Right now, I store the user’s password hash using 10 iterations of the Argon2 Hash, and process logins using the Argon2 built-in hash compare. As I understand it, the Google OAuth2 would replace this part just fine. However, it’s the next part that I’m concerned about.
For each user, I generate a unique, random string 50 characters long using the Apache Commons RandomStringUtils.random(...); function (incorporating both letters & numbers). I use this string as the master encryption key for the account. All the user’s content is encrypted using this key. The actual encryption is done using the Spring AES Password-Based Cipher, where this master key string is passed in as the encryption password.
But here’s the problem: I then generate a random BCrypt Salt (configured to 12 iterations) unique for each user, and store this salt raw in the user’s account record in the DB. When the user creates their account, I take their raw text password, and hash it with BCrypt, using their account unique BCrypt salt. This BCrypt hash of their raw text password is the Meta-Key I use to encrypt their master key. I then store their encrypted master key in their Account DB record. Then, when the user logs in, I take their raw text password, generate the hash again using the salt stored in the DB, and use it as the Meta-Key to decrypt their master key from the DB. I then re-encrypt their master key using the server’s global private key (the same for all users), and then embed the Server-Encrypted master key into a JWT token and send it to the client to act as their stateless Token. When they make a request, they pass the token back, the webserver extracts the master key from the token, decrypts it with the server’s global private key, and then uses it to decrypt the user’s data.
Unless you see something majorly wrong with my design, my questions is: if I switch to OAuth, the user will no longer be providing me with a password, I will only be getting a token from the OAuth provider (Google in this case). But that token will be different each time they log in. I need something that is unique to each user, that is also static and will be exactly the same every time they log in. But it also needs to be private & non-reproducible, so I can’t use something like their Google Account GUID (assuming they even give you access to something like that), because that would be accessible to other apps/users.
Does OAuth provide any mechanism for a some kind of token/ID which is both Private & Unique to the User/App pair, and also Static across separate logins? At this point, I’m coming to the conclusion that OAuth is impossible in my situation, but I thought I’d see if anyone had any ideas. I’m open to redesigning my security process, but it must maintain a unique encryption key for each user.
Thank you for your time.