feat: create service session
This commit is contained in:
@ -17,20 +17,10 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ApiToken struct {
|
||||
Token string
|
||||
Expiration float64
|
||||
}
|
||||
|
||||
type ApiTokens struct {
|
||||
ID ApiToken
|
||||
Access ApiToken
|
||||
Refresh ApiToken
|
||||
}
|
||||
|
||||
func (h *OAuthHandler) signApiTokens(user *repository.User, apiService *repository.ApiService, nonce *string) (*ApiTokens, error) {
|
||||
func (h *OAuthHandler) signApiTokens(user *repository.User, apiService *repository.ApiService, nonce *string) (*types.SignedToken, *types.SignedToken, *types.SignedToken, error) {
|
||||
accessExpiresIn := 15 * time.Minute
|
||||
accessExpiresAt := time.Now().Add(accessExpiresIn)
|
||||
accessJTI := uuid.New()
|
||||
|
||||
accessClaims := types.ApiClaims{
|
||||
Permissions: []string{},
|
||||
@ -40,12 +30,13 @@ func (h *OAuthHandler) signApiTokens(user *repository.User, apiService *reposito
|
||||
Audience: jwt.ClaimStrings{apiService.ClientID},
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(accessExpiresAt),
|
||||
ID: accessJTI.String(),
|
||||
},
|
||||
}
|
||||
|
||||
access, err := util.SignJwtToken(accessClaims, h.cfg.Jwt.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
var roles = []string{"user"}
|
||||
@ -56,6 +47,7 @@ func (h *OAuthHandler) signApiTokens(user *repository.User, apiService *reposito
|
||||
|
||||
idExpiresIn := 15 * time.Minute
|
||||
idExpiresAt := time.Now().Add(idExpiresIn)
|
||||
idJTI := uuid.New()
|
||||
|
||||
idClaims := types.IdTokenClaims{
|
||||
Email: user.Email,
|
||||
@ -70,16 +62,18 @@ func (h *OAuthHandler) signApiTokens(user *repository.User, apiService *reposito
|
||||
Audience: jwt.ClaimStrings{apiService.ClientID},
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(idExpiresAt),
|
||||
ID: idJTI.String(),
|
||||
},
|
||||
}
|
||||
|
||||
idToken, err := util.SignJwtToken(idClaims, h.cfg.Jwt.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
refreshExpiresIn := 24 * time.Hour
|
||||
refreshExpiresAt := time.Now().Add(refreshExpiresIn)
|
||||
refreshJTI := uuid.New()
|
||||
|
||||
refreshClaims := types.ApiRefreshClaims{
|
||||
UserID: user.ID.String(),
|
||||
@ -89,28 +83,16 @@ func (h *OAuthHandler) signApiTokens(user *repository.User, apiService *reposito
|
||||
Audience: jwt.ClaimStrings{apiService.ClientID},
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(refreshExpiresAt),
|
||||
ID: refreshJTI.String(),
|
||||
},
|
||||
}
|
||||
|
||||
refresh, err := util.SignJwtToken(refreshClaims, h.cfg.Jwt.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return &ApiTokens{
|
||||
ID: ApiToken{
|
||||
Token: idToken,
|
||||
Expiration: idExpiresIn.Seconds(),
|
||||
},
|
||||
Access: ApiToken{
|
||||
Token: access,
|
||||
Expiration: accessExpiresIn.Seconds(),
|
||||
},
|
||||
Refresh: ApiToken{
|
||||
Token: refresh,
|
||||
Expiration: refreshExpiresIn.Seconds(),
|
||||
},
|
||||
}, nil
|
||||
return types.NewSignedToken(idToken, idExpiresAt, idJTI), types.NewSignedToken(access, accessExpiresAt, accessJTI), types.NewSignedToken(refresh, refreshExpiresAt, refreshJTI), nil
|
||||
}
|
||||
|
||||
func (h *OAuthHandler) tokenEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
@ -174,40 +156,71 @@ func (h *OAuthHandler) tokenEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
fmt.Printf("Code received: %s\n", code)
|
||||
|
||||
session, err := h.cache.GetAuthCode(r.Context(), code)
|
||||
codeSession, err := h.cache.GetAuthCode(r.Context(), code)
|
||||
if err != nil {
|
||||
log.Printf("ERR: Failed to find session under the code %s: %v\n", code, err)
|
||||
web.Error(w, "no session found under this auth code", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("DEBUG: Fetched code session: %#v\n", session)
|
||||
log.Printf("DEBUG: Fetched code session: %#v\n", codeSession)
|
||||
|
||||
apiService, err := h.repo.GetApiServiceCID(r.Context(), session.ClientID)
|
||||
apiService, err := h.repo.GetApiServiceCID(r.Context(), codeSession.ClientID)
|
||||
if err != nil {
|
||||
log.Printf("ERR: Could not find API service with client %s: %v\n", session.ClientID, err)
|
||||
log.Printf("ERR: Could not find API service with client %s: %v\n", codeSession.ClientID, err)
|
||||
web.Error(w, "service is not registered", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
if session.ClientID != clientId {
|
||||
if codeSession.ClientID != clientId {
|
||||
web.Error(w, "invalid auth", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.repo.FindUserId(r.Context(), uuid.MustParse(session.UserID))
|
||||
user, err := h.repo.FindUserId(r.Context(), uuid.MustParse(codeSession.UserID))
|
||||
if err != nil {
|
||||
web.Error(w, "requested user not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
tokens, err := h.signApiTokens(&user, &apiService, &session.Nonce)
|
||||
id, access, refresh, err := h.signApiTokens(&user, &apiService, &codeSession.Nonce)
|
||||
if err != nil {
|
||||
log.Println("ERR: Failed to sign api tokens:", err)
|
||||
web.Error(w, "failed to sign tokens", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("DEBUG: Created api tokens: %v\n\n%v\n\n%v\n", id.ID.String(), access.ID.String(), refresh.ID.String())
|
||||
|
||||
userId, err := uuid.Parse(codeSession.UserID)
|
||||
if err != nil {
|
||||
log.Printf("ERR: Failed to parse user '%s' uuid: %v\n", codeSession.UserID, err)
|
||||
web.Error(w, "failed to sign tokens", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
ipAddr := util.GetClientIP(r)
|
||||
ua := r.UserAgent()
|
||||
|
||||
session, err := h.repo.CreateServiceSession(r.Context(), repository.CreateServiceSessionParams{
|
||||
ServiceID: apiService.ID,
|
||||
ClientID: apiService.ClientID,
|
||||
UserID: &userId,
|
||||
ExpiresAt: &refresh.ExpiresAt,
|
||||
LastActive: nil,
|
||||
IpAddress: &ipAddr,
|
||||
UserAgent: &ua,
|
||||
AccessTokenID: &access.ID,
|
||||
RefreshTokenID: &refresh.ID,
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("ERR: Failed to create new service session: %v\n", err)
|
||||
web.Error(w, "failed to create session", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("INFO: Service session created for '%s' client_id with '%s' id\n", apiService.ClientID, session.ID.String())
|
||||
|
||||
type Response struct {
|
||||
IdToken string `json:"id_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
@ -219,11 +232,11 @@ func (h *OAuthHandler) tokenEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
response := Response{
|
||||
IdToken: tokens.ID.Token,
|
||||
IdToken: id.Token,
|
||||
TokenType: "Bearer",
|
||||
AccessToken: tokens.Access.Token,
|
||||
RefreshToken: tokens.Refresh.Token,
|
||||
ExpiresIn: tokens.Access.Expiration,
|
||||
AccessToken: access.Token,
|
||||
RefreshToken: refresh.Token,
|
||||
ExpiresIn: access.ExpiresAt.Sub(time.Now()).Seconds(),
|
||||
Email: user.Email,
|
||||
}
|
||||
|
||||
@ -269,7 +282,7 @@ func (h *OAuthHandler) tokenEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
tokens, err := h.signApiTokens(&user, &apiService, nil)
|
||||
id, access, refresh, err := h.signApiTokens(&user, &apiService, nil)
|
||||
|
||||
type Response struct {
|
||||
IdToken string `json:"id_token"`
|
||||
@ -280,11 +293,11 @@ func (h *OAuthHandler) tokenEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
response := Response{
|
||||
IdToken: tokens.ID.Token,
|
||||
IdToken: id.Token,
|
||||
TokenType: "Bearer",
|
||||
AccessToken: tokens.Access.Token,
|
||||
RefreshToken: tokens.Refresh.Token,
|
||||
ExpiresIn: tokens.Access.Expiration,
|
||||
AccessToken: access.Token,
|
||||
RefreshToken: refresh.Token,
|
||||
ExpiresIn: access.ExpiresAt.Sub(time.Now()).Seconds(),
|
||||
}
|
||||
|
||||
log.Printf("DEBUG: refresh - sending following response: %#v\n", response)
|
||||
|
Reference in New Issue
Block a user