Fetching gitlab repo list : says "401 Unauthorized" - go

I am trying to get repo list from gitlab using OAuth token.
My code looks something like this ... ("github.com/xanzy/go-gitlab")
repositories := []string{}
client, _ := gitlab.NewClient(gitRepoRequest.Token, gitlab.WithBaseURL("https://gitlab.com/api/v4"))
fmt.Println("client...", client.ContainerRegistry)
projects, _, projectListErr := client.Projects.ListProjects(&gitlab.ListProjectsOptions{})
for _, project := range projects {
fmt.Println("ID===", project.ID)
fmt.Println("NAME===", project.Name)
}
if projectListErr != nil {
// return err
}
I am not able to get the project list.. the "projectListErr" says ...
GET https://gitlab.com/api/v4/projects: 401 {message: 401 Unauthorized}
I am confident about the token value because I am getting list of all branches for a repo using the same token, that code looks like ... ("github.com/go-git/go-git/v5")
rem := git.NewRemote(gitMemory.NewStorage(), &gitConfig.RemoteConfig{
Name: "origin",
URLs: []string{gitBranchesRequest.Repository},
})
refs, listErr := rem.List(&git.ListOptions{
Auth: &gitHttp.BasicAuth{Username: gitUserName, Password: gitBranchesRequest.Token},
})
Does that mean there is an issue with the library that I am using ? github.com/xanzy/go-gitlab

It depends on the type of token you are using.
For instance, a project access token might very well give you access to the list of all branches for a repository (for that project).
But for using the /projects API, 401 means the authentication information is not valid or is missing.
So make sure to use a PAT (Personal Access Token), linked to a user, not a project.
The OP Keval Bhogayata adds in the comments:
I have found the issue.
The library I am using ("xanzy/go-gitlab"), has different client creation functions for different tokens.
I have been using the function that supports personal access token. Instead I was supposed to use "NewOAuthClient" !
// NewOAuthClient returns a new GitLab API client. To use API methods which
// require authentication, provide a valid oauth token.
func NewOAuthClient(token string, options ...ClientOptionFunc) (*Client, error)

Related

OAuth2 and/or JWT: make sure users are authenticated

This question is not about the difference between Oauth2 and JWT.
I'm building an application using Go and the Gin framework. This application should be able to register users with Facebook SSO. Once a user is registered, I want to make sure that all my endpoints will require an authenticated user. So far I have implemented the Oauth flow, and it works. I'm using the goth/gothic libraries. It looks like this:
router.GET("/auth/:provider", func(c *gin.Context) {
q := c.Request.URL.Query()
q.Add("provider", c.Param("provider"))
c.Request.URL.RawQuery = q.Encode()
// try to get the user without re-authenticating
if gothUser, err := gothic.CompleteUserAuth(c.Writer, c.Request); err == nil {
logger.Debug("Re-using existing credentials", gothUser)
} else {
logger.Debug("Starting auth flow")
gothic.BeginAuthHandler(c.Writer, c.Request)
}
})
router.GET("/callback", func(c *gin.Context) {
user, err := gothic.CompleteUserAuth(c.Writer, c.Request)
l.Debug(user)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
}
})
I'm a bit stuck regarding what to do next. All the articles I could find describe how to get the oauth token, but not how to use it. Should I use the info I get back from facebook (e.g: name, email) to build a JWT token to secure my endpoints? Or is there a way to securely/easily use the oauth token to do that?
I could use a pointer to be on the right track, as you know implementing the auth mechanism is quite important and I couldn't find a guide describing good practices.

Generate a JWT from GitHub App PEM private key in Go

I'm trying to use GitHub App and I need to generate a JWT for authenticating (https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#generating-a-private-key)
I'm trying to do that using Goland.
How can I generate a JWT from PEM private key in Go??
The jwt-go library has all the tools you need, and is fairly well documented. You can find it at https://github.com/golang-jwt/jwt.
Assuming you understand what JWTs are and how they're structured, and that you can get that PEM key as a []byte, the process is roughly:
Add "github.com/golang-jwt/jwt/v4" to your imports.
Create a set of claims, which can include the RegisteredClaims type and any custom claims you may need.
Create the token with jwt.NewWithClaims() - you'll need to provide the appropriate signing method. I've primarily used RS256.
Create the JWT string from the token with token.SignedString().
In practice, it will look something like this:
imports "github.com/golang-jwt/jwt/v4"
type MyCustomClaims struct {
*jwt.RegisteredClaims
FooClaim int
BarClaim string
}
func CreateJWT(pemKey []byte) string {
// expires in 60 minutes
expiration := time.Now().Add(time.Second * 3600)
claims := MyCustomClaims{
RegisteredClaims: &jwt.RegisteredClaims{
Issuer: "Example Code Inc.",
ExpiresAt: jwt.NewNumericDate(expiration),
Subject: "JWT Creation",
},
FooClaim: 123,
BarClaim: "bar",
}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
privateKey, _ := jwt.ParseRSAPrivateKeyFromPEM(pemKey)
myJWT, _ := jwt.SignedString(privateKey)
return myJWT
}
I suggest reading code from this repository:
https://github.com/bradleyfalzon/ghinstallation
I don't know why, but the code in the answer from #JesseB above didn't work for me - it always throws: 401 Unauthorized. Although this repository does use golang-jwt package internally

400 Bad request when generating the Google API access token using Go iamcredentials client API

I am trying to implement iamcredentials Go API client to generate an Access Token to access some Google APIs via REST API, I am using this code
package main
import (
"context"
"log"
"google.golang.org/api/iamcredentials/v1"
)
func main() {
iamcredentialsService, err := iamcredentials.NewService(context.Background())
if err != nil {
log.Println("error initialize iamcredential Service ", err)
return
}
accessTokenCall := iamcredentialsService.Projects.ServiceAccounts.GenerateAccessToken(
"projects/-/serviceAccounts/some-sa#some-project-id.iam.gserviceaccount.com:generateAccessToken",
&iamcredentials.GenerateAccessTokenRequest{
Scope: []string{
iamcredentials.CloudPlatformScope,
},
},
)
iamResp, err := accessTokenCall.Do()
if err != nil {
log.Println("error generate access token", err)
return
}
log.Println(iamResp)
}
But when I tried to run the above snippet, I got this message
go run main.go
error generate access token googleapi: Error 400: Request contains an invalid argument., badRequest
Is there any way to check which one is causing the above response? I am not sure since there isn't any good example of implementation. Any help would be appreciated, Thanks.
Notes :
I have checked following documentation on this topic https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials and this https://pkg.go.dev/google.golang.org/api/iamcredentials/v1#pkg-overview
I have already setup the Service account using Service Account Token Creator role on IAM and also enabled the IAM API from the console
Also I have added GOOGLE_APPLICATION_CREDENTIALS to the environment variables as suggested
#DanielFarrell is right, you need to remove the :generateAccessToken at the end. Here the documentation in the code. Don't hesitate to explore it, it's open source ;)
// GenerateAccessToken: Generates an OAuth 2.0 access token for a
// service account.
//
// - name: The resource name of the service account for which the
// credentials are requested, in the following format:
// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-`
// wildcard character is required; replacing it with a project ID is
// invalid.
func (r *ProjectsServiceAccountsService) GenerateAccessToken(name string, generateaccesstokenrequest *GenerateAccessTokenRequest) *ProjectsServiceAccountsGenerateAccessTokenCall {
c := &ProjectsServiceAccountsGenerateAccessTokenCall{s: r.s, urlParams_: make(gensupport.URLParams)}
c.name = name
c.generateaccesstokenrequest = generateaccesstokenrequest
return c
}

Google access token does not work within cloud functions

I'm using this example provided under cloud functions to make a GET request to another GCP API:
import (
"context"
"fmt"
"io"
"google.golang.org/api/idtoken"
)
func makeGetRequest(w io.Writer, targetURL string) error {
ctx := context.Background()
client, err := idtoken.NewClient(ctx, targetURL)
if err != nil {
return fmt.Errorf("idtoken.NewClient: %v", err)
}
resp, err := client.Get(targetURL)
if err != nil {
return fmt.Errorf("client.Get: %v", err)
}
defer resp.Body.Close()
if _, err := io.Copy(w, resp.Body); err != nil {
return fmt.Errorf("io.Copy: %v", err)
}
return nil
}
but when I log the request sent I don't see any authorization header and I get the following error:
"Request
had invalid authentication credentials. Expected OAuth 2 access token, login cookie
or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.\"
I have given serviceAccountTokenCreator and the target GCP API admin permissions to the service account that's used to create the cloud function.
Am I misunderstanding what the documentation is saying? It seems like the authorization header should be automatically added.
It might be easier for you to not build the request from scratch and use Client Libraries instead. It provides idiomatic, generated or hand-written code in each language, making the Cloud API simple and intuitive to use. It also handles authentication for you.
From what you're following, the client automatically adds an "Authorization" header so that shouldn't be the problem. You're also trying to follow an example that generates an Identity Token, because calling a Cloud Function endpoint that has authentication requires an Identity token. This is different on your use case, because calling GCP APIs require an OAuth 2 access token. This link explains the difference between the two.
There are ways to generate an access token programmatically such as getting them from the metadata server as I did in my other answer (it's in Python but you can also do it in Golang). However, I suggest learning more on how Client Libraries work and test it for yourself. There are many examples shown on GitHub to get you started.

Scopes Not Present in JWT Claim in Golang and Goa

I am using the excellent goa package to generate my API in Go.
However, I am having an issue with its security middleware and when I submit a bearer token to my controllers, I get "authorization failed" because of "scopes:null". I am using Auth0 for authentication and it is generating the bearer token. The exact error in Postman is:
{"id":"xOUR882s","code":"jwt_security_error","status":401,"detail":"authorization failed: required 'scopes' not present in JWT claim","meta":{"required":["read:meta"],"scopes":null}}
However, my token does include the required scope read:meta. jwt.io gives back the following decoded bearer:
{
"iss": "https://learnlogic.au.auth0.com/",
"sub": "exJMkK7hXX56lrLwoTqna3s0jh7Gq67e#clients",
"aud": "https://api.learn-logic.com",
"exp": 1494855336,
"iat": 1494768936,
"scopes": "read:meta"
}
I am hoping someone can help me workout why, as I don't really understand what is going on in middleware/jwt.go in the goa project which may be found here. My only thought is that something about the Auth0 formatted bearer is not compatible with the parseClaimScopes function in middleware/jwt.go, but I don't know what.
I have the following main.go code:
b, err := ioutil.ReadFile("util/jwt.key")
if err != nil {
return
}
block, _ := pem.Decode([]byte(b))
var cert *x509.Certificate
cert, _ = x509.ParseCertificate(block.Bytes)
rsaPublicKey := cert.PublicKey.(*rsa.PublicKey)
fmt.Println(rsaPublicKey.N)
fmt.Println(rsaPublicKey.E)
fmt.Println(cert)
var keyx = []jwt.Key{rsaPublicKey}
var jwtResolver = jwt.NewSimpleResolver(keyx)
app.UseJWTMiddleware(service, jwt.New(jwtResolver, nil, app.NewJWTSecurity()))
The certificate I am reading in is the same one used in jwt.io to decode the bearer token.
Any help is much appreciated.
According to this ticket https://github.com/goadesign/goa/issues/1228, the problem was due to the fact there was only a support for a claim with a singular name "scope" and not the plural "scopes". This PR https://github.com/goadesign/goa/pull/1399, added the plural version.

Resources