claude-code-api 0.1.3

OpenAI-compatible API gateway for Claude Code CLI
#![allow(dead_code)]

use axum::{
    extract::Request,
    http::{header, StatusCode},
    middleware::Next,
    response::Response,
};
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use chrono::{Duration, Utc};

#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub sub: String,
    pub exp: i64,
    pub iat: i64,
}

pub struct AuthManager {
    secret: String,
    enabled: bool,
}

impl AuthManager {
    pub fn new(secret: String, enabled: bool) -> Self {
        Self { secret, enabled }
    }
    
    pub fn generate_token(&self, user_id: &str, expiry_hours: i64) -> Result<String, jsonwebtoken::errors::Error> {
        let now = Utc::now();
        let exp = now + Duration::hours(expiry_hours);
        
        let claims = Claims {
            sub: user_id.to_string(),
            exp: exp.timestamp(),
            iat: now.timestamp(),
        };
        
        encode(&Header::default(), &claims, &EncodingKey::from_secret(self.secret.as_bytes()))
    }
    
    pub fn verify_token(&self, token: &str) -> Result<Claims, jsonwebtoken::errors::Error> {
        decode::<Claims>(
            token,
            &DecodingKey::from_secret(self.secret.as_bytes()),
            &Validation::default(),
        ).map(|data| data.claims)
    }
}

pub async fn auth_middleware(
    req: Request,
    next: Next,
) -> Result<Response, StatusCode> {
    let auth_header = req
        .headers()
        .get(header::AUTHORIZATION)
        .and_then(|h| h.to_str().ok());
    
    if let Some(auth_header) = auth_header
        && auth_header.starts_with("Bearer ") {
            return Ok(next.run(req).await);
        }
    
    Err(StatusCode::UNAUTHORIZED)
}