use std::fmt;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
pub const DEVICE_CODE_GRANT_URN: &str = "urn:ietf:params:oauth:grant-type:device_code";
#[cfg(feature = "token-exchange")]
pub const TOKEN_EXCHANGE_GRANT_URN: &str = "urn:ietf:params:oauth:grant-type:token-exchange";
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum GrantType {
#[serde(rename = "authorization_code")]
AuthorizationCode,
#[serde(rename = "refresh_token")]
RefreshToken,
#[serde(rename = "client_credentials")]
ClientCredentials,
#[serde(rename = "urn:ietf:params:oauth:grant-type:device_code")]
DeviceCode,
#[cfg(feature = "token-exchange")]
#[serde(rename = "urn:ietf:params:oauth:grant-type:token-exchange")]
TokenExchange,
}
impl GrantType {
pub fn parse(s: &str) -> Option<Self> {
match s {
"authorization_code" => Some(GrantType::AuthorizationCode),
"refresh_token" => Some(GrantType::RefreshToken),
"client_credentials" => Some(GrantType::ClientCredentials),
DEVICE_CODE_GRANT_URN => Some(GrantType::DeviceCode),
#[cfg(feature = "token-exchange")]
TOKEN_EXCHANGE_GRANT_URN => Some(GrantType::TokenExchange),
_ => None,
}
}
pub fn as_str(self) -> &'static str {
match self {
GrantType::AuthorizationCode => "authorization_code",
GrantType::RefreshToken => "refresh_token",
GrantType::ClientCredentials => "client_credentials",
GrantType::DeviceCode => DEVICE_CODE_GRANT_URN,
#[cfg(feature = "token-exchange")]
GrantType::TokenExchange => TOKEN_EXCHANGE_GRANT_URN,
}
}
}
impl fmt::Display for GrantType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnknownGrantType(pub String);
impl fmt::Display for UnknownGrantType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "unknown grant_type {:?}", self.0)
}
}
impl std::error::Error for UnknownGrantType {}
impl FromStr for GrantType {
type Err = UnknownGrantType;
fn from_str(s: &str) -> Result<Self, Self::Err> {
GrantType::parse(s).ok_or_else(|| UnknownGrantType(s.to_string()))
}
}
#[cfg(test)]
#[path = "tests/grant.rs"]
mod tests;