Skip to content

Commit

Permalink
feat(auth) complete sso login flow
Browse files Browse the repository at this point in the history
Signed-off-by: jeyem <[email protected]>
  • Loading branch information
jeyem committed Feb 11, 2025
1 parent c62d624 commit 54bd8bf
Show file tree
Hide file tree
Showing 17 changed files with 342 additions and 56 deletions.
53 changes: 53 additions & 0 deletions cmd/add_access/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

import (
"context"
"flag"
"fmt"
"log"
"socious-id/src/apps/auth"
"socious-id/src/apps/models"
"socious-id/src/apps/utils"
"socious-id/src/config"
"time"

database "github.com/socious-io/pkg_database"
)

var (
name = flag.String("n", "example", "access name")
description = flag.String("d", "example description", "access description")
)

func main() {
config.Init("config.yml")

database.Connect(&database.ConnectOption{
URL: config.Config.Database.URL,
SqlDir: config.Config.Database.SqlDir,
MaxRequests: 5,
Interval: 30 * time.Second,
Timeout: 5 * time.Second,
})

defer database.Close()
secret := utils.RandomString(24)
clientSecret, _ := auth.HashPassword(secret)

access := &models.Access{
Name: *name,
Description: *description,
ClientID: utils.RandomString(8),
ClientSecret: clientSecret,
}
ctx := context.Background()

if err := access.Create(ctx); err != nil {
log.Fatal(err)
}
fmt.Println("one time client secret visibility, take copy please")
fmt.Println(" ------------------------ ")
fmt.Printf("Client ID : `%s` \n", access.ClientID)
fmt.Printf("Client Secret : `%s` \n", secret)
fmt.Println(" ------------------------ ")
}
2 changes: 1 addition & 1 deletion src/apps/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func CheckPasswordHash(password, hash string) error {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
}

func GenerateFullTokens(id, email string) (map[string]any, error) {
func Signin(id, email string) (map[string]any, error) {
accessToken, err := GenerateToken(id, email, false)
if err != nil {
return nil, err
Expand Down
173 changes: 132 additions & 41 deletions src/apps/models/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,24 @@ import (

"github.com/google/uuid"
"github.com/jmoiron/sqlx/types"
"github.com/lib/pq"
database "github.com/socious-io/pkg_database"
)

type Access struct {
ID uuid.UUID `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Description string `db:"description" json:"description"`
Scopes pq.StringArray `db:"scopes" json:"scopes"`
Logo *uuid.UUID `db:"logo" json:"logo"`
ClientID string `db:"client_id" json:"client_id"`
ClientSecret string `db:"client_secret" json:"-"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
}

type OTP struct {
ID uuid.UUID `db:"id" json:"id"`
Code string `db:"code" json:"code"`
Type OTPType `db:"type" json:"type"`
UserID uuid.UUID `db:"user_id" json:"user_id"`
AuthSessionID uuid.UUID `db:"auth_session_id" json:"auth_session_id"`
ExpireAt time.Time `db:"expire_at" json:"expire_at"`
VerifiedAt *time.Time `db:"verified_at" json:"verified_at"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
ID uuid.UUID `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Description string `db:"description" json:"description"`
ClientID string `db:"client_id" json:"client_id"`
ClientSecret string `db:"client_secret" json:"-"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
}

type AuthSession struct {
ID uuid.UUID `db:"id" json:"id"`
AccessID uuid.UUID `db:"access_id" json:"access_id"`
RedirectURL string `db:"redirect_url" json:"redirect_url"`

AccessID uuid.UUID `db:"access_id" json:"access_id"`
Access *Access `db:"-" json:"access"`
AccessJson types.JSONText `db:"access" json:"-"`

Expand All @@ -48,16 +35,98 @@ type AuthSession struct {
CreatedAt time.Time `db:"created_at" json:"created_at"`
}

type OTP struct {
ID uuid.UUID `db:"id" json:"id"`
Code string `db:"code" json:"code"`
Type OTPType `db:"type" json:"type"`

UserID uuid.UUID `db:"user_id" json:"user_id"`
User User `db:"-" json:"user"`
UserJson types.JSONText `db:"user" json:"-"`

AuthSessionID *uuid.UUID `db:"auth_session_id" json:"auth_session_id"`
AuthSession *AuthSession `db:"-" json:"auth_session"`
AuthSessionJson *types.JSONText `db:"auth_session" json:"-"`

ExpireAt time.Time `db:"expire_at" json:"expire_at"`
VerifiedAt *time.Time `db:"verified_at" json:"verified_at"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
}

func (Access) TableName() string {
return "accesses"
}

func (Access) FetchQuery() string {
return "auth/fetch_access"
}

func (a *Access) Create(ctx context.Context) error {
rows, err := database.Query(
ctx,
"auth/create_access",
a.Name, a.Description, a.ClientID, a.ClientSecret,
)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
if err := rows.StructScan(a); err != nil {
return err
}
}
return nil
}

func (AuthSession) TableName() string {
return "auth_sessions"
}

func (AuthSession) FetchQuery() string {
return "auth/fetch_auth_session"
}

func (a *AuthSession) Create(ctx context.Context) error {
// @IMPORTANT @TODO: read from DB
s, err := GetAuthSession(uuid.New())
rows, err := database.Query(
ctx,
"auth/create_auth_session",
a.RedirectURL, a.AccessID,
)
if err != nil {
return err
}
utils.Copy(s, a)
defer rows.Close()
for rows.Next() {
if err := rows.StructScan(a); err != nil {
return err
}
}
return nil
}

func (a *AuthSession) Verify(ctx context.Context) error {
rows, err := database.Query(ctx, "auth/auth_session_verify", a.ID)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
if err := rows.StructScan(a); err != nil {
return err
}
}
return nil
}

func (OTP) TableName() string {
return "otps"
}

func (OTP) FetchQuery() string {
return "auth/fetch_otp"
}

func (o *OTP) Create(ctx context.Context) error {
codeLength := 6
if o.Type == SSOOTP {
Expand All @@ -67,7 +136,7 @@ func (o *OTP) Create(ctx context.Context) error {
rows, err := database.Query(
ctx,
"auth/create_otp",
o.Type, o.RefID, o.Code,
o.Type, o.UserID, o.AuthSessionID, o.Code,
)
if err != nil {
return err
Expand All @@ -81,23 +150,45 @@ func (o *OTP) Create(ctx context.Context) error {
return nil
}

func GetAuthSession(id uuid.UUID) (*AuthSession, error) {
// @IMPORTANT @TODO: read from DB
access, _ := GetAccessByClientID("")
return &AuthSession{
ID: id,
RedirectURL: "https://app.socious.io",
Access: access,
}, nil
func (o *OTP) Verify(ctx context.Context) error {
if o.AuthSession != nil {
if err := o.AuthSession.Verify(ctx); err != nil {
return err
}
}
rows, err := database.Query(ctx, "auth/otp_verify", o.ID)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
if err := rows.StructScan(o); err != nil {
return err
}
}
return nil
}

func GetAccessByClientID(clientID string) (*Access, error) {
// @IMPORTANT @TODO: read from DB
return &Access{
ID: uuid.New(),
Name: "Socious",
Description: "Socious",
ClientID: "test",
ClientSecret: "test",
}, nil
a := new(Access)
if err := database.Get(a, "auth/fetch_access_by_client_id"); err != nil {
return nil, err
}
return a, nil
}

func GetAuthSession(id uuid.UUID) (*AuthSession, error) {
a := new(AuthSession)
if err := database.Fetch(a, id); err != nil {
return nil, err
}
return a, nil
}

func GetOTPByCode(code string) (*OTP, error) {
o := new(OTP)
if err := database.Get(o, "auth/fetch_otp_by_code", code); err != nil {
return nil, err
}
return o, nil
}
14 changes: 14 additions & 0 deletions src/apps/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"strings"
)

const RandCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func Copy(src interface{}, dst interface{}) error {
bytes, err := json.Marshal(src)
if err != nil {
Expand Down Expand Up @@ -75,3 +77,15 @@ func GenerateRandomDigits(digits int) int {

return int(n.Int64() + lowerBound)
}

func RandomString(length int) string {
b := make([]byte, length)
for i := range b {
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(RandCharset))))
if err != nil {
return RandomString(length)
}
b[i] = RandCharset[num.Int64()]
}
return string(b)
}
Loading

0 comments on commit 54bd8bf

Please sign in to comment.