Crates.io | github-oidc |
lib.rs | github-oidc |
version | 0.3.0 |
source | src |
created_at | 2024-09-04 18:35:31.00466 |
updated_at | 2024-09-16 02:18:32.89506 |
description | Rust crate for validating GitHub OIDC tokens |
homepage | |
repository | https://github.com/the-cafe/github-oidc |
max_upload_size | |
id | 1363638 |
size | 28,080 |
TL;DR
cargo add github-oidc
or add the dependency to your Cargo.toml
[dependencies]
github-oidc = "insert_latest_version_here" # e.g. 0.1.4
github-oidc enables secure, credential-free authentication for custom GitHub Actions workflow integrations.
Here's the perfect ideal scenario:
Your Github Actions Workflow needs to interact with protected resources (e.g., production databases, cloud services, or internal APIs).
You set up a custom OIDC provider service (e.g., using railway.app) to handle authentication for your GitHub Actions.
In your GitHub Actions workflow:
github-oidc
to validate the token and check the github claims (e.g., repository name, workflow, ref).The GitHub Action uses these temporary credentials to perform the you desired operations.
Credentials expire shortly after the job completes.
use github_oidc::{GithubJWKS, validate_github_token};
use std::sync::Arc;
use tokio::sync::RwLock;
async fn custom_endpoint(
token_request: web::Json<TokenRequest>,
data: web::Data<AppState>,
) -> impl Responder {
let jwks = data.jwks.clone();
match validate_github_token(&token_request.token, jwks, Some("https://github.com/your-username")).await {
Ok(claims) => {
log::info!("Token validated successfully");
HttpResponse::Ok().json(claims)
}
Err(e) => {
log::error!("Token validation error: {:?}", e);
HttpResponse::BadRequest().body(format!("Invalid token: {}", e))
}
}
}
#[actix_web::main]
async fn main() -> Result<()> {
env_logger::init_from_env(Env::default().default_filter_or("debug"));
color_eyre::install()?;
let github_oidc_url = "your_oidc_server_url"
let jwks = Arc::new(RwLock::new(fetch_jwks(github_oidc_url).await?));
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(AppState { jwks: jwks.clone() }))
.route("/token", web::post().to(custom_endpoint))
})
.bind("0.0.0.0:3000")?
.run()
.await?;
Ok(())
}
name: Get and Validate JWT
on:
workflow_dispatch:
jobs:
get_and_validate_jwt:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Get JWT
id: get_token
uses: actions/github-script@v6
with:
script: |
const token = await core.getIDToken()
core.setOutput('token', token)
- name: Validate JWT
env:
OIDC_SERVICE_URL: ${{ secrets.OIDC_SERVICE_URL }}
run: |
TOKEN="${{ steps.get_token.outputs.token }}"
RESPONSE=$(curl -s -X POST $OIDC_SERVICE_URL \
-H "Content-Type: application/json" \
-d "{\"token\": \"$TOKEN\"}")
echo "OIDC Service Response: $RESPONSE"
if [[ $RESPONSE == *"Invalid token"* ]]; then
echo "::error::Token validation failed: $RESPONSE"
exit 1
elif [[ $RESPONSE == *"error"* ]]; then
echo "::warning::Unexpected error occurred: $RESPONSE"
exit 1
elif [[ -z "$RESPONSE" ]]; then
echo "::error::Empty response from OIDC service"
exit 1
else
echo "::notice::Token validated successfully"
echo "$RESPONSE" | jq .
fi