My blog has moved! Read this post at: https://blog.ferrata.dev/github-app-authentication-in-darklang/
My friend introduced me to a project named darklang, or simply Dark. It's a serverless and deployless backend builder. A unique approach that sets it apart (at least for me) is stated on its Introduction page:
Darklang is an integrated language, framework, and editor for building web backends: REST API endpoints, asynchronous background workers, scheduled jobs, and persistent storage. Dark's framework is tightly coupled to the infrastructure, and as you write code you're able to develop from real incoming requests/traces.
Also, it is a functional language!
Dark is a statically-typed functional/imperative hybrid, based loosely on ML. Dark has implicit returns, and makes heavy use of pipelines and functions like List::map
So, having quite a bit of backend and API experience, I was intrigued! But mainly, I wanted to test-drive Dark and see how it felt.
I started a small project that I will share later; it uses GitHub API with App access, and I needed a way to authenticate my GitHub app. Since Dark is under active development, it doesn't have all the bells and whistles yet, but it's impressive how many features are already implemented.
This is a small, wanna-be-guide on creating and authenticating your GitHub app with Dark.
1. Create a new GitHub App
2. Generate a private key
3. Add secrets to your project in Dark:
- APP_ID - contains GitHub App ID; it can be found in the About section of your GitHub App
- APP_PEM - contains a PEM certificate from the previous step
4. Install the GitHub App into your profile
5. Create a new function, github_authenticate, in your Dark functions. Add the following implementation:
let now = Date::now let jwt = JWT::signAndEncodev1 APP_PEM { iat : now |>Date::toSeconds exp : Date::add now 60 * 10 - 1 |>Date::toSeconds iss : APP_ID } let headers = { Accepts : "application/vnd.github.v3+json" } |>Dict::set "User-Agent" "DarkGithub" |>Dict::merge HttpClient::bearerTokenv1 jwt let installation = HttpClient::getv5 "https://api.github.com/app/installations" Dict::empty headers |>\r -> r.body |>List::getAtv1 0 let tokensUrl = String::join ["https://api.github.com/app/installations", toString installation.id,"access_tokens"] "/" let response = HttpClient::postv5 tokensUrl Dict::empty Dict::empty headers Ok response.body
Here is how it looks in Dark:
Now we can test it with the following REPL:
let auth = github_authenticate let headers = { Accepts : "application/vnd.github.v3+json" } |>Dict::set "User-Agent" "DarkGithub" |>Dict::merge HttpClient::bearerTokenv1 auth.token let response = HttpClient::getv5 "https://api.github.com/users/ferrata" Dict::empty headers Ok response.body
...and look! It works! 😊
References: