diff --git a/cmd/api/handlers-api.go b/cmd/api/handlers-api.go index 9575f4f..37cb9cd 100644 --- a/cmd/api/handlers-api.go +++ b/cmd/api/handlers-api.go @@ -2,11 +2,13 @@ package main import ( "encoding/json" + "errors" "fmt" "myapp/internal/cards" "myapp/internal/models" "net/http" "strconv" + "strings" "time" "github.com/go-chi/chi/v5" @@ -298,6 +300,46 @@ func (app *application) CreateAuthToken(w http.ResponseWriter, r *http.Request) _ = app.writeJSON(w, http.StatusOK, payload) } -func (app *application) CheckAuthentication(w http.ResponseWriter, r *http.Request) { - app.invalidCredentials(w) +func (app *application) authenticateToken(r *http.Request) (*models.User, error) { + authorizationHeader := r.Header.Get("Authorization") + if authorizationHeader == "" { + return nil, errors.New("no authorization header received") + } + + headerParts := strings.Split(authorizationHeader, " ") + if len(headerParts) != 2 || headerParts[0] != "Bearer" { + return nil, errors.New("no authorization header received") + } + + token := headerParts[1] + if len(token) != 26 { + return nil, errors.New("authentication token wrong size") + } + + // get the user from the tokens table + user, err := app.DB.GetUserForToken(token) + if err != nil { + return nil, errors.New("no matching user found") + } + + return user, nil +} + +func (app *application) CheckAuthentication(w http.ResponseWriter, r *http.Request) { + // validate the token, and get associated user + user, err := app.authenticateToken(r) + if err != nil { + app.errorLog.Println(err) + app.invalidCredentials(w) + return + } + + // valid user + var payload struct { + Error bool `json:"error"` + Message string `json:"message"` + } + payload.Error = false + payload.Message = fmt.Sprintf("authenticated user %s", user.Email) + app.writeJSON(w, http.StatusOK, payload) } diff --git a/internal/models/tokens.go b/internal/models/tokens.go index 81a5ecc..7112508 100644 --- a/internal/models/tokens.go +++ b/internal/models/tokens.go @@ -71,3 +71,27 @@ func (m *DBModel) InsertToken(t *Token, u User) error { } return nil } + +func (m *DBModel) GetUserForToken(token string) (*User, error) { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + tokenHash := sha256.Sum256([]byte(token)) + var user User + + query := `SELECT u.id, u.first_name, u.last_name, u.email + FROM users u + INNER JOIN tokens t on (u.id = t.user_id) + WHERE t.token_hash = ?` + + err := m.DB.QueryRowContext(ctx, query, tokenHash[:]).Scan( + &user.ID, + &user.FirstName, + &user.LastName, + &user.Email, + ) + if err != nil { + return nil, err + } + return &user, nil +} diff --git a/static/js/common.js b/static/js/common.js index 00df869..e40c1aa 100644 --- a/static/js/common.js +++ b/static/js/common.js @@ -75,7 +75,7 @@ export function checkAuth(api) { const requestOptions = { method: "POST", - Headers: myHeaders, + headers: myHeaders, } fetch(api + "/api/is-authenticated", requestOptions)