62 lines
1.7 KiB
Go

package auth
import (
"context"
"errors"
"fmt"
firebase "firebase.google.com/go/v4"
fbauth "firebase.google.com/go/v4/auth"
"google.golang.org/api/option"
"watch-party-backend/internal/config"
)
// TokenVerifier hides Firebase client behind a small interface for testing.
type TokenVerifier interface {
Verify(ctx context.Context, token string) (*fbauth.Token, error)
}
// AdminManager can set admin claims.
type AdminManager interface {
TokenVerifier
SetAdmin(ctx context.Context, uid string, admin bool) error
}
// FirebaseAuth verifies Firebase ID tokens.
type FirebaseAuth struct {
client *fbauth.Client
}
// NewFirebaseAuth builds the Firebase client from config.
func NewFirebaseAuth(ctx context.Context, cfg config.FirebaseConfig) (*FirebaseAuth, error) {
creds, err := cfg.CredentialsBytes()
if err != nil {
return nil, err
}
if len(creds) == 0 {
return nil, errors.New("firebase credentials empty")
}
app, err := firebase.NewApp(ctx, &firebase.Config{ProjectID: cfg.ProjectID}, option.WithCredentialsJSON(creds))
if err != nil {
return nil, fmt.Errorf("init firebase app: %w", err)
}
client, err := app.Auth(ctx)
if err != nil {
return nil, fmt.Errorf("init firebase auth client: %w", err)
}
return &FirebaseAuth{client: client}, nil
}
// Verify checks a Firebase ID token and returns its claims.
func (f *FirebaseAuth) Verify(ctx context.Context, token string) (*fbauth.Token, error) {
return f.client.VerifyIDToken(ctx, token)
}
// SetAdmin sets or clears the custom claim "admin" for a given uid.
func (f *FirebaseAuth) SetAdmin(ctx context.Context, uid string, admin bool) error {
return f.client.SetCustomUserClaims(ctx, uid, map[string]interface{}{
"admin": admin,
})
}