1
0
Fork 0

add POST /login/oauth/access_token

This commit is contained in:
Cyborus 2024-05-22 16:34:58 -04:00
parent 716192d4d4
commit bf8d6e1a3b
No known key found for this signature in database

View file

@ -11,8 +11,6 @@ pub struct Forgejo {
mod generated; mod generated;
pub use generated::structs;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum ForgejoError { pub enum ForgejoError {
#[error("url must have a host")] #[error("url must have a host")]
@ -154,6 +152,22 @@ impl Forgejo {
Ok(self.execute(request).await?.bytes().await?) Ok(self.execute(request).await?.bytes().await?)
} }
/// Requests a new OAuth2 access token
///
/// More info at [Forgejo's docs](https://forgejo.org/docs/latest/user/oauth2-provider).
pub async fn oauth_get_access_token(
&self,
body: structs::OAuthTokenRequest<'_>,
) -> Result<structs::OAuthToken, ForgejoError> {
let url = self.url.join("login/oauth/access_token").unwrap();
let request = self.client.post(url).json(&body).build()?;
let response = self.execute(request).await?;
match response.status().as_u16() {
200 => Ok(response.json().await?),
_ => Err(ForgejoError::UnexpectedStatusCode(response.status())),
}
}
fn get(&self, path: &str) -> reqwest::RequestBuilder { fn get(&self, path: &str) -> reqwest::RequestBuilder {
let url = self.url.join("api/v1/").unwrap().join(path).unwrap(); let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
self.client.get(url) self.client.get(url)
@ -202,6 +216,56 @@ struct ErrorMessage {
// url: Url // url: Url
} }
pub mod structs {
pub use crate::generated::structs::*;
/// A Request for a new OAuth2 access token
///
/// More info at [Forgejo's docs](https://forgejo.org/docs/latest/user/oauth2-provider).
#[derive(serde::Serialize)]
#[serde(tag = "grant_type")]
pub enum OAuthTokenRequest<'a> {
/// Request for getting an access code for a confidential app
///
/// The `code` field must have come from sending the user to
/// `/login/oauth/authorize` in their browser
#[serde(rename = "authorization_code")]
Confidential {
client_id: &'a str,
client_secret: &'a str,
code: &'a str,
redirect_uri: url::Url,
},
/// Request for getting an access code for a public app
///
/// The `code` field must have come from sending the user to
/// `/login/oauth/authorize` in their browser
#[serde(rename = "authorization_code")]
Public {
client_id: &'a str,
code_verifier: &'a str,
code: &'a str,
redirect_uri: url::Url,
},
/// Request for refreshing an access code
#[serde(rename = "refresh_token")]
Refresh {
refresh_token: &'a str,
client_id: &'a str,
client_secret: &'a str,
},
}
#[derive(serde::Deserialize)]
pub struct OAuthToken {
pub access_token: String,
pub refresh_token: String,
pub token_type: String,
/// Number of seconds until the access token expires.
pub expires_in: u32,
}
}
// Forgejo can return blank strings for URLs. This handles that by deserializing // Forgejo can return blank strings for URLs. This handles that by deserializing
// that as `None` // that as `None`
fn none_if_blank_url<'de, D: serde::Deserializer<'de>>( fn none_if_blank_url<'de, D: serde::Deserializer<'de>>(