-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Ory Kratos Integration. #198
Changes from 6 commits
7b8727b
79b3c8f
2965204
ad9eae1
e69b0f2
b751b30
9efcfec
7212778
c7777db
3e43356
55039ca
7fee31b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package config | ||
|
||
// DBConfig type of db config object | ||
type KratosConfig struct { | ||
IsEnabled bool `envconfig:"KRATOS_ENABLED"` | ||
BaseUrl string `envconfig:"SERVE_PUBLIC_BASE_URL"` | ||
UIUrl string `envconfig:"SELF_SERVICE_DEFAULT_BROWSER_RETURN_URL"` | ||
AdminUrl string `envconfig:"SERVE_ADMIN_BASE_URL"` | ||
PublicUrl string `envconfig:"SERVE_PUBLIC_BASE_URL"` | ||
CookieExpirationTime string `envconfig:"KRATOS_COOKIE_EXPIRATION_TIME"` | ||
} | ||
|
||
type KratosUserDetails struct { | ||
Identity struct { | ||
ID string `json:"id"` | ||
Traits struct { | ||
Name struct { | ||
Last string `json:"last"` | ||
First string `json:"first"` | ||
} `json:"name"` | ||
Email string `json:"email"` | ||
} `json:"traits"` | ||
CreatedAt string `json:"created_at"` | ||
UpdatedAt string `json:"updated_at"` | ||
} `json:"identity"` | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package v1 | |
import ( | ||
"database/sql" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"time" | ||
|
||
|
@@ -14,13 +15,15 @@ import ( | |
"github.com/Improwised/golang-api/services" | ||
"github.com/Improwised/golang-api/utils" | ||
"github.com/doug-martin/goqu/v9" | ||
"github.com/go-resty/resty/v2" | ||
"github.com/gofiber/fiber/v2" | ||
"go.uber.org/zap" | ||
"gopkg.in/go-playground/validator.v9" | ||
) | ||
|
||
type AuthController struct { | ||
userService *services.UserService | ||
userModel *models.UserModel | ||
logger *zap.Logger | ||
config config.AppConfig | ||
} | ||
|
@@ -35,6 +38,7 @@ func NewAuthController(goqu *goqu.Database, logger *zap.Logger, config config.Ap | |
|
||
return &AuthController{ | ||
userService: userSvc, | ||
userModel: &userModel, | ||
logger: logger, | ||
config: config, | ||
}, nil | ||
|
@@ -94,3 +98,62 @@ func (ctrl *AuthController) DoAuth(c *fiber.Ctx) error { | |
|
||
return utils.JSONSuccess(c, http.StatusOK, user) | ||
} | ||
|
||
// DoKratosAuth authenticate user with kratos session id | ||
// swagger:route GET /kratos/auth Auth none | ||
// | ||
// Authenticate user with kratos session id. | ||
// | ||
// Consumes: | ||
// - application/json | ||
// | ||
// Schemes: http, https | ||
// Responses: | ||
// 400: GenericResFailBadRequest | ||
// 500: GenericResError | ||
func (ctrl *AuthController) DoKratosAuth(c *fiber.Ctx) error { | ||
kratosID := c.Locals(constants.KratosID) | ||
|
||
if kratosID.(string) == "" { | ||
return utils.JSONError(c, http.StatusBadRequest, constants.ErrKratosIDEmpty) | ||
} | ||
|
||
kratosClient := resty.New().SetBaseURL(ctrl.config.Kratos.BaseUrl+"/sessions").SetHeader("Cookie", fmt.Sprintf("%v=%v", constants.KratosCookie, kratosID)).SetHeader("accept", "application/json") | ||
|
||
kratosUser := config.KratosUserDetails{} | ||
res, err := kratosClient.R().SetResult(&kratosUser).Get("/whoami") | ||
if err != nil || res.StatusCode() != http.StatusOK { | ||
return utils.JSONError(c, http.StatusInternalServerError, constants.ErrKratosAuth) | ||
} | ||
|
||
userStruct := models.User{} | ||
userStruct.KratosID = kratosUser.Identity.ID | ||
userStruct.FirstName = kratosUser.Identity.Traits.Name.First | ||
userStruct.LastName = kratosUser.Identity.Traits.Name.Last | ||
userStruct.Email = kratosUser.Identity.Traits.Email | ||
userStruct.CreatedAt = kratosUser.Identity.CreatedAt | ||
userStruct.UpdatedAt = kratosUser.Identity.UpdatedAt | ||
|
||
user, err := ctrl.userModel.InsertKratosUser(userStruct) | ||
if err != nil { | ||
return utils.JSONError(c, http.StatusInternalServerError, constants.ErrKratosDataInsertion) | ||
} | ||
|
||
cookieExpirationTime, err := time.ParseDuration(ctrl.config.Kratos.CookieExpirationTime) | ||
if err != nil { | ||
return utils.JSONError(c, http.StatusInternalServerError, constants.ErrKratosCookieTime) | ||
} | ||
|
||
userCookie := &fiber.Cookie{ | ||
Name: constants.KratosCookie, | ||
Value: kratosID.(string), | ||
Expires: time.Now().Add(cookieExpirationTime), | ||
} | ||
|
||
c.Cookie(userCookie) | ||
c.Redirect(ctrl.config.Kratos.UIUrl) | ||
|
||
c.Locals(constants.KratosUserDetails, user) | ||
c.Next() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Shaktizala What is purpose of it? L154 will already redirect on UI There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, forgot to remove it, it was there when I was not doing redirection. will update it. |
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,12 @@ | ||
-- +migrate Up | ||
CREATE TABLE IF NOT EXISTS users ( | ||
id CHAR (20) PRIMARY KEY, | ||
kratos_id CHAR(50), | ||
first_name VARCHAR (50) NOT NULL, | ||
last_name VARCHAR (50) NOT NULL, | ||
email VARCHAR (50) UNIQUE NOT NULL, | ||
password VARCHAR (100) NOT NULL, | ||
roles TEXT NOT NULL, | ||
password VARCHAR (100), | ||
roles TEXT, | ||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Shaktizala What is the purpose of using
c.Locals
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's used to fetch kratosID into the next handle. It means we can add it to locals from here and fetch it from the next handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Shaktizala Is it middleware? Middleware shouldn't be in controller
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's not middleware. used to pass an ID from middleware to next handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, is
DoKratosAuth
middleware?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's not middleware. It's an endpoint on which kratos will redirect after successful login/registration.