I want to implement a system that after user signs up, user will receive an email includes a link to verify this email is for that user.
The way I generate the token for verifying the email is like this:
import (
"crypto/rand"
"encoding/base64"
)
func generateToken() (string, error) {
b := make([]byte, 35)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(b), nil
}
But what I want to ask is if this method is OK? How to make all the token generated by this method is unique ?
What is the normal way to implement this system ?
Please give me some ideas and tell me if this method of generating token is good.
Thanks.
Check out https://godoc.org/code.google.com/p/go-uuid/uuid#NewRandom.
And you may want to consider storing this in a database with the email address and perhaps an expiry date / time so that the verification doesn't stay there forever. You may only want to allow people to verify within 24 hours, or 7 days and so on. Have another job that periodically cleans expired and non-verified emails.
Two points:
To expand on these points…
You're dealing with a set of outstanding verification requests. That is:
As you can see, at any given time you only have several outstanding verification requests. Hence this situation has two important properties:
So, the approach to generating a new token is as follows:
Generate something hard-to-guess.
Compare it with the tokens bound to the outstanding/pending verification requests persisted in your storage.
If you find an outstanding request with the same token, you have a collision so go to step (1) and repeat.
Otherwise the token is OK so proceed with it and persist the data about this request.
Once the request passed verification, remove it from your storage.
Exact algorythm for generating tokens does not matter much. I'd say an UUID or something looking like SHA-256/512 calculated over some random data is OK.
No need to be unique. You could look for more secure/complex solutions but what about simply putting a random number in hex such that
strconv.FormatInt(rand.Int63(), 16)