# GitHub App Token [![Hackage](https://img.shields.io/hackage/v/github-app-token.svg?style=flat)](https://hackage.haskell.org/package/github-app-token) [![Stackage Nightly](http://stackage.org/package/github-app-token/badge/nightly)](http://stackage.org/nightly/package/github-app-token) [![Stackage LTS](http://stackage.org/package/github-app-token/badge/lts)](http://stackage.org/lts/package/github-app-token) [![CI](https://github.com/freckle/github-app-token/actions/workflows/ci.yml/badge.svg)](https://github.com/freckle/github-app-token/actions/workflows/ci.yml) [Generate an installation access token for a GitHub App][docs] [docs]: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation ## Getting an AccessToken ```haskell import Prelude import Data.Aeson (FromJSON) import Data.ByteString.Char8 qualified as BS8 import Data.Text (Text) import Data.Text.Encoding (encodeUtf8) import GHC.Generics (Generic) import GitHub.App.Token import Network.HTTP.Simple import Network.HTTP.Types.Header (hAuthorization, hUserAgent) import System.Environment getAppToken :: IO AccessToken getAppToken = do appId <- AppId . read <$> getEnv "GITHUB_APP_ID" privateKey <- PrivateKey . BS8.pack <$> getEnv "GITHUB_PRIVATE_KEY" installationId <- InstallationId . read <$> getEnv "GITHUB_INSTALLATION_ID" let creds = AppCredentials {appId, privateKey} generateInstallationToken creds installationId ``` ## Using an AccessToken ```haskell data Repo = Repo { name :: Text , description :: Text } deriving stock (Eq, Show, Generic) deriving anyclass FromJSON getRepo :: AccessToken -> String -> IO Repo getRepo token name = do req <- parseRequest $ "https://api.github.com/repos/" <> name resp <- httpJSON $ addRequestHeader hAuthorization ("Bearer " <> encodeUtf8 token.token) $ addRequestHeader hUserAgent "github-app-token/example" $ req pure $ getResponseBody resp ``` ## Getting a Scoped AccessToken By default, a token is created with repositories access and permissions as defined in the installation configuration. Either of these can be changed by using `generateInstallationTokenScoped`: ```haskell getScopedAppToken :: IO AccessToken getScopedAppToken = do appId <- AppId . read <$> getEnv "GITHUB_APP_ID" privateKey <- PrivateKey . BS8.pack <$> getEnv "GITHUB_PRIVATE_KEY" installationId <- InstallationId . read <$> getEnv "GITHUB_INSTALLATION_ID" let creds = AppCredentials {appId, privateKey} create = mempty { repositories = ["freckle/github-app-token"] , permissions = contents Read } generateInstallationTokenScoped create creds installationId ``` ## Getting an AccessToken for an Owner ```haskell getOwnerAppToken :: IO AccessToken getOwnerAppToken = do appId <- AppId . read <$> getEnv "GITHUB_APP_ID" privateKey <- PrivateKey . BS8.pack <$> getEnv "GITHUB_PRIVATE_KEY" let creds = AppCredentials {appId, privateKey} generateOwnerToken creds $ Org "freckle" ``` ## Getting a Self-Refreshing AccessToken Installation tokens are good for one hour, after which point using them will respond with `401 Unauthorized`. To avoid this, you can use the `GitHub.App.Token.Refresh` module to maintain a background thread that refreshes the token as necessary: ```haskell getRepos :: [String] -> IO [Repo] getRepos names = do ref <- refreshing getAppToken repos <- for names $ \name -> do token <- getRefresh ref getRepo token name cancelRefresh ref pure repos ``` --- [CHANGELOG](./CHANGELOG.md) | [LICENSE](./LICENSE)