github4s icon indicating copy to clipboard operation
github4s copied to clipboard

GithubApp Auth

Open loonydev opened this issue 4 years ago • 12 comments

Hi, As I understand, for now this library don't support GithubApps authorization?

If so, I want to discuss the best way for implementation.

In my code I used trait GithubAuth with method def getAuthHeader():String. GithubClient taken instance of GithubAuth and call this function for token. In case of PAT it's return token from constructor, in case of private key it's looks like:

class GithubKeyAuth(privateKeyContent: String, appId: String) extends GithubAuth {

  implicit val clock: Clock = Clock.systemUTC
  // build PrivateKey instance from string
  private val privateKey = GithubKeyAuth.getPrivateKey(privateKeyContent)

 // generate valid JWT token using PrivateKey
  override def getAuthHeader(): String = {
    "Bearer " + Jwt.encode(JwtClaim({
      s"""{"iss":$appId}"""
    }).issuedNow.expiresIn(10), privateKey, JwtAlgorithm.RS256)
  }
}

WDYT?

loonydev avatar Sep 22 '20 09:09 loonydev

You're right we don't support github apps authorization. However, I'm not sure about the best way to go about it as we don't want to handle jwt tokens directly in the library for example.

BenFradet avatar Sep 23 '20 11:09 BenFradet

Agreed, maybe we can make GithubClient to accept instance of GithubAuth, so the user can use by default GithubPatAuth, in other cases they need to define own class.

But if it's part of Github Auth flow user will do same code over and over.

loonydev avatar Sep 23 '20 15:09 loonydev

So, do you have any suggestions how to implement it? I can do that, by I need to be sure that I don't waste a time.

loonydev avatar Sep 28 '20 09:09 loonydev

maybe we can make GithubClient to accept instance of GithubAuth, so the user can use by default GithubPatAuth, in other cases they need to define own class.

I'm :+1: on that

BenFradet avatar Sep 29 '20 09:09 BenFradet

But as I mention before, users will do same code over and over and not in the best way. It's like give them domain and say, use own http sender.

loonydev avatar Sep 29 '20 09:09 loonydev

We can add that code as documentation, it doesn't seem to me like the usage will be so huge that it would need to be part of the library.

BenFradet avatar Oct 01 '20 10:10 BenFradet

Okay, next week I'm going to prepare this changes and will discuss it with real example.

loonydev avatar Oct 01 '20 10:10 loonydev

@loonydev Hi! Are you still planning to make a PR with this changes?

kusaeva avatar Nov 05 '20 15:11 kusaeva

Morning @kusaeva, not yet, it's in plan, but not in a near future. If you have a time to make it, it would be great.

loonydev avatar Nov 09 '20 07:11 loonydev

Hello - I'm interested about the status of this issue

We have a standalone service in our infrastructure that requires broad access to GH's REST api and the repositories under our organisation (DHL-Parcel) - preferably using the github4s library and authorise not via a personal access token - but either via JWT tokens or - as requested in this issue - via GH Apps authorisation.

We did try the new AccessToken feature to get this working but weren't able to. The main issue seems to be the Authorisation: token header being hardcoded in the library, but we might not understand the way the new features was intended to be used. In that case an example would help us.

If authorisation via JWT or GH App tokens is currently not possible we would able to spend some time on getting this to work with github4s provided that we get some help and pointers on how the preferred integration should look like in the API.

Thanks in advance :)

nmcb avatar May 23 '23 12:05 nmcb

Hi @nmcb, thanks for your interest.

This is how it's currently built.

We have an algebra that allows generating tokens:

https://github.com/47degrees/github4s/blob/9c18225cc61f756aace9ddcb5d134720c882edb0/github4s/shared/src/main/scala/github4s/algebras/AccessToken.scala#L31-L34

This algebra has a single implementation called StaticAccessToken. You pass a token, and it returns as a pure value.

https://github.com/47degrees/github4s/blob/9c18225cc61f756aace9ddcb5d134720c882edb0/github4s/shared/src/main/scala/github4s/interpreters/StaticAccessToken.scala#L25-L29

When you create a new Github4s client, it's creates an instance of that algebra to use it internally:

https://github.com/47degrees/github4s/blob/9c18225cc61f756aace9ddcb5d134720c882edb0/github4s/shared/src/main/scala/github4s/Github.scala#L53

This is then used to create the internal GithubAPIv3 algebra:

https://github.com/47degrees/github4s/blob/9c18225cc61f756aace9ddcb5d134720c882edb0/github4s/shared/src/main/scala/github4s/Github.scala#L31

That, in a similar way, pass it to the internal HTTPClient algebra:

https://github.com/47degrees/github4s/blob/9c18225cc61f756aace9ddcb5d134720c882edb0/github4s/shared/src/main/scala/github4s/modules/GithubAPIs.scala#L32

The HTTPClient uses the withAccessToken to get the token and pass it to the RequestBuilder

https://github.com/47degrees/github4s/blob/9c18225cc61f756aace9ddcb5d134720c882edb0/github4s/shared/src/main/scala/github4s/http/HttpClient.scala#L65-L69

The RequestBuilder stores the token in a authHeader map, where the key is Authorization, and the value is s"token $token".

https://github.com/47degrees/github4s/blob/9c18225cc61f756aace9ddcb5d134720c882edb0/github4s/shared/src/main/scala/github4s/http/RequestBuilder.scala#L44-L48

This is mapped to a Header.Raw

https://github.com/47degrees/github4s/blob/9c18225cc61f756aace9ddcb5d134720c882edb0/github4s/shared/src/main/scala/github4s/http/Http4sSyntax.scala#L50

Potential solution

@loonydev's approach looks good, so I've created a draft with a potential solution:

  • https://github.com/47degrees/github4s/pull/875/files

In that way, you can implement your algebra for generating auth headers, having complete control. Let me know your thoughts. The docs need to be updated accordingly.

fedefernandez avatar May 31 '23 09:05 fedefernandez

thanks @fedefernandez! we'll give it a try.

cc @thijsnissen

nmcb avatar May 31 '23 14:05 nmcb