markbates / goth

Package goth provides a simple, clean, and idiomatic way to write authentication packages for Go web applications.
https://blog.gobuffalo.io/goth-needs-a-new-maintainer-626cd47ca37b
MIT License
5.2k stars 566 forks source link

Google authorization claiming "Bad Request" when I include scopes #530

Closed MeirionL closed 6 days ago

MeirionL commented 6 months ago

I've got working code for authorizing google users. I wanted to specifically get access to some YouTube API Data, so I added the appropriate scopes to my google provider. Now when I go through the authorization process, the scopes seem to work, as the page asking me to select each one I want to provide access to appears, but now after I click continue to finish the authorization, I get an error that says "http: panic serving [::1]:42206: interface conversion: interface {} is nil, not string".

This error is happening because I am apparently making a bad request when I use the gothic.CompleteUserAuth() function in my login handler. Inside this function, at line 204 of goth/gothic/gothic.go, sess.Authorize is returning an error that says 'oauth2: "invalid_grant" "Bad Request"'. Why this is happening only when I include any scopes in my Google provider creation, I don't know, but I've provided the code for my login handler and the code for my goth session creation. This is happening with all Google scopes, not just YouTube ones, and I'm not having this issue at all with my Twitch scopes.

Any help or advice on this would be greatly appreciated, thanks.

handler_login.go:

package main

import (
    "context"
    "fmt"
    "net/http"

    "github.com/go-chi/chi/v5"
    "github.com/markbates/goth/gothic"
)

func (cfg *apiConfig) handlerAuthLogin(w http.ResponseWriter, r *http.Request) {
    provider := chi.URLParam(r, "provider")
    r = r.WithContext(context.WithValue(context.Background(), "provider", provider))
    if user, err := gothic.CompleteUserAuth(w, r); err == nil {
        http.Redirect(w, r, "http://localhost:5173", http.StatusFound)
        cfg.createUser(w, r, user)
        return
    } else {
        fmt.Println("it is time to begin logging in!")
        gothic.BeginAuthHandler(w, r)
    }
}

auth.go:

package auth

import (
    "os"

    "github.com/gorilla/sessions"
    "github.com/joho/godotenv"
    "github.com/markbates/goth"
    "github.com/markbates/goth/gothic"
    "github.com/markbates/goth/providers/google"
    "github.com/markbates/goth/providers/twitch"
)

const (
    MaxAge = 86400 * 30
    IsProd = false
)

func NewAuth() {
    godotenv.Load(".env")

    key := os.Getenv("RANDOM_KEY")
    googleClientID := os.Getenv("GOOGLE_CLIENT_ID")
    googleClientSecret := os.Getenv("GOOGLE_CLIENT_SECRET")
    twitchClientID := os.Getenv("TWITCH_CLIENT_ID")
    twitchClientSecret := os.Getenv("TWITCH_CLIENT_SECRET")

    store := sessions.NewCookieStore([]byte(key))
    store.MaxAge(MaxAge)

    store.Options.Path = "/"
    store.Options.HttpOnly = true
    store.Options.Secure = IsProd

    gothic.Store = store

    goth.UseProviders(
        google.New(
            googleClientID, googleClientSecret, "http://localhost:8080/auth/google",
            "https://www.googleapis.com/auth/youtube.readonly",
            "https://www.googleapis.com/auth/youtube.channel-memberships.creator",
            "https://www.googleapis.com/auth/yt-analytics.readonly",
        ),
        twitch.New(
            twitchClientID, twitchClientSecret, "http://localhost:8080/auth/twitch",
            "channel:read:subscriptions",
            "channel:read:vips",
            "moderation:read",
            "moderator:read:followers",
            "user:read:broadcast",
            "user:read:email",
        ),
    )
}