Skip to content

Instantly share code, notes, and snippets.

@codesword
Last active February 21, 2024 14:48
Show Gist options
  • Star 32 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save codesword/1b997a259d2509c3b0ea7f087c9b5466 to your computer and use it in GitHub Desktop.
Save codesword/1b997a259d2509c3b0ea7f087c9b5466 to your computer and use it in GitHub Desktop.
package auth
import (
"context"
"net/http"
"strings"
"google.golang.org/grpc/metadata"
"github.com/andela/micro-api-gateway/pb/authorization"
"github.com/andela/micro-api-gateway/pb/user"
"github.com/labstack/echo"
)
// NewOAuth2Provider returns a generic OAuth 2.0 backend endpoint.
func Authorize(fn func(string) (Claims, error)) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
if c.Path() == "/favicon.ico" {
return nil
}
if c.Path() == "/" {
return next(c)
}
if c.Path() == "/health" {
return next(c)
}
if c.Request().Header.Get("x-forwarded-proto") == "http" {
to := "https://" + c.Request().Host + c.Request().URL.RequestURI()
return c.Redirect(redirectStatusCode, to)
}
return handleOtherRouteAccess(fn, next, c)
}
}
}
func handleOtherRouteAccess(fn func(string) (Claims, error), next echo.HandlerFunc, c echo.Context) error {
var claims Claims
if apiToken := c.Request().Header.Get("api-token"); apiToken != "" {
u, err := usersClient.ValidateAPIToken(context.Background(), &user.APIToken{Token: apiToken})
if err != nil {
return respondWithError(401, "invalid api token", c)
}
claims = NewClaims(u)
claims.Permissions, _ = getPermission(u.Roles)
} else {
var tokenString string
jwtToken, err := c.Cookie("jwt-token")
if err != nil || jwtToken == nil {
if tokenString = getTokenFromRequest(c.Request()); tokenString == "" {
return respondWithError(401, "token not present", c)
}
} else {
tokenString = jwtToken.Value
}
claims, err = fn(tokenString)
if err != nil {
return respondWithError(401, "invalid token", c)
}
}
in := authorization.AuthorizeRequest{}
in.Method = c.Request().Method
in.Url = c.Request().URL.Path
for _, id := range claims.Permissions {
in.PermissionIds = append(in.PermissionIds, id)
}
if _, err := authorizationClient.Authorize(context.Background(), &in); err != nil {
return respondWithError(401, "user not authorized", c)
}
ctx := metadata.NewContext(
context.Background(),
metadata.Pairs("author_id", claims.Id, "author_name", claims.Name, "author_email", claims.Email),
)
c.Set("claims", claims)
c.Set("context", ctx)
c.Set("user_id", claims.Id)
return next(c)
}
func respondWithError(code int, message string, c echo.Context) error {
return c.JSON(code, echo.Map{"error": message})
}
func getTokenFromRequest(req *http.Request) string {
authStr := req.Header.Get("Authorization")
if !strings.HasPrefix(authStr, "Bearer ") {
return ""
}
return authStr[7:]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment