Add authentication, authorization, and team-scoped access control
Implement email/password auth with JWT sessions and API key auth for sandbox lifecycle. Users get a default team on signup; sandboxes, snapshots, and API keys are scoped to teams. - Add user, team, users_teams, and team_api_keys tables (goose migrations) - Add JWT middleware (Bearer token) for user management endpoints - Add API key middleware (X-API-Key header, SHA-256 hashed) for sandbox ops - Add signup/login handlers with transactional user+team creation - Add API key CRUD endpoints (create/list/delete) - Replace owner_id with team_id on sandboxes and templates - Update all handlers to use team-scoped queries - Add godotenv for .env file loading - Update OpenAPI spec and test UI with auth flows
This commit is contained in:
124
internal/db/api_keys.sql.go
Normal file
124
internal/db/api_keys.sql.go
Normal file
@ -0,0 +1,124 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
// source: api_keys.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const deleteAPIKey = `-- name: DeleteAPIKey :exec
|
||||
DELETE FROM team_api_keys WHERE id = $1 AND team_id = $2
|
||||
`
|
||||
|
||||
type DeleteAPIKeyParams struct {
|
||||
ID string `json:"id"`
|
||||
TeamID string `json:"team_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteAPIKey(ctx context.Context, arg DeleteAPIKeyParams) error {
|
||||
_, err := q.db.Exec(ctx, deleteAPIKey, arg.ID, arg.TeamID)
|
||||
return err
|
||||
}
|
||||
|
||||
const getAPIKeyByHash = `-- name: GetAPIKeyByHash :one
|
||||
SELECT id, team_id, name, key_hash, key_prefix, created_by, created_at, last_used FROM team_api_keys WHERE key_hash = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetAPIKeyByHash(ctx context.Context, keyHash string) (TeamApiKey, error) {
|
||||
row := q.db.QueryRow(ctx, getAPIKeyByHash, keyHash)
|
||||
var i TeamApiKey
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.TeamID,
|
||||
&i.Name,
|
||||
&i.KeyHash,
|
||||
&i.KeyPrefix,
|
||||
&i.CreatedBy,
|
||||
&i.CreatedAt,
|
||||
&i.LastUsed,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const insertAPIKey = `-- name: InsertAPIKey :one
|
||||
INSERT INTO team_api_keys (id, team_id, name, key_hash, key_prefix, created_by)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING id, team_id, name, key_hash, key_prefix, created_by, created_at, last_used
|
||||
`
|
||||
|
||||
type InsertAPIKeyParams struct {
|
||||
ID string `json:"id"`
|
||||
TeamID string `json:"team_id"`
|
||||
Name string `json:"name"`
|
||||
KeyHash string `json:"key_hash"`
|
||||
KeyPrefix string `json:"key_prefix"`
|
||||
CreatedBy string `json:"created_by"`
|
||||
}
|
||||
|
||||
func (q *Queries) InsertAPIKey(ctx context.Context, arg InsertAPIKeyParams) (TeamApiKey, error) {
|
||||
row := q.db.QueryRow(ctx, insertAPIKey,
|
||||
arg.ID,
|
||||
arg.TeamID,
|
||||
arg.Name,
|
||||
arg.KeyHash,
|
||||
arg.KeyPrefix,
|
||||
arg.CreatedBy,
|
||||
)
|
||||
var i TeamApiKey
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.TeamID,
|
||||
&i.Name,
|
||||
&i.KeyHash,
|
||||
&i.KeyPrefix,
|
||||
&i.CreatedBy,
|
||||
&i.CreatedAt,
|
||||
&i.LastUsed,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const listAPIKeysByTeam = `-- name: ListAPIKeysByTeam :many
|
||||
SELECT id, team_id, name, key_hash, key_prefix, created_by, created_at, last_used FROM team_api_keys WHERE team_id = $1 ORDER BY created_at DESC
|
||||
`
|
||||
|
||||
func (q *Queries) ListAPIKeysByTeam(ctx context.Context, teamID string) ([]TeamApiKey, error) {
|
||||
rows, err := q.db.Query(ctx, listAPIKeysByTeam, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TeamApiKey
|
||||
for rows.Next() {
|
||||
var i TeamApiKey
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.TeamID,
|
||||
&i.Name,
|
||||
&i.KeyHash,
|
||||
&i.KeyPrefix,
|
||||
&i.CreatedBy,
|
||||
&i.CreatedAt,
|
||||
&i.LastUsed,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateAPIKeyLastUsed = `-- name: UpdateAPIKeyLastUsed :exec
|
||||
UPDATE team_api_keys SET last_used = NOW() WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) UpdateAPIKeyLastUsed(ctx context.Context, id string) error {
|
||||
_, err := q.db.Exec(ctx, updateAPIKeyLastUsed, id)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user