dbots/services/auth/auth.go

58 lines
1.4 KiB
Go

package auth
import (
"context"
"crypto/rand"
"encoding/hex"
"codeberg.org/nextgo/dbots/internal/db"
"codeberg.org/nextgo/dbots/internal/discord"
)
type Service struct {
q *db.Queries
client *discord.Client
}
func NewService(q *db.Queries, client *discord.Client) *Service {
return &Service{q: q, client: client}
}
// Callback exchanges the OAuth code for a Discord access token,
// fetches the Discord user, and upserts them in the database.
// It returns the db.User and the raw Discord access token
// (needed so the caller can store it in the session if desired).
func (s *Service) Callback(ctx context.Context, code string) (*db.User, *discord.TokenResponse, error) {
tok, err := s.client.ExchangeCode(ctx, code)
if err != nil {
return nil, nil, err
}
dUser, err := s.client.GetCurrentUser(ctx, tok.AccessToken)
if err != nil {
return nil, nil, err
}
user, err := s.q.GetUser(ctx, dUser.ID)
if err != nil {
user, err = s.q.CreateUser(ctx, db.CreateUserParams{
ID: dUser.ID,
Username: dUser.Username,
})
if err != nil {
return nil, nil, err
}
}
return user, tok, nil
}
// GenerateState returns a cryptographically random hex string for
// the OAuth2 state parameter.
func GenerateState() (string, error) {
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}