oidc.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. use openidconnect::{
  2. core::{CoreClient, CoreErrorResponseType, CoreIdToken, CoreResponseType, CoreTokenResponse},
  3. reqwest::async_http_client,
  4. url::Url,
  5. AuthenticationFlow, AuthorizationCode, ClaimsVerificationError, ClientId, CsrfToken, IssuerUrl,
  6. LogoutRequest, Nonce, ProviderMetadataWithLogout, RedirectUrl, RefreshToken, RequestTokenError,
  7. StandardErrorResponse,
  8. };
  9. use serde::{Deserialize, Serialize};
  10. use crate::{props::client::ClientProps, DIOXUS_FRONT_CLIENT_ID};
  11. #[derive(Clone, Debug, Default)]
  12. pub struct ClientState {
  13. pub oidc_client: Option<ClientProps>,
  14. }
  15. /// State that holds the nonce and authorization url and the nonce generated to log in an user
  16. #[derive(Clone, Deserialize, Serialize, Default)]
  17. pub struct AuthRequestState {
  18. pub auth_request: Option<AuthRequest>,
  19. }
  20. #[derive(Clone, Deserialize, Serialize)]
  21. pub struct AuthRequest {
  22. pub nonce: Nonce,
  23. pub authorize_url: String,
  24. }
  25. /// State the tokens returned once the user is authenticated
  26. #[derive(Debug, Deserialize, Serialize, Default, Clone)]
  27. pub struct AuthTokenState {
  28. /// Token used to identify the user
  29. pub id_token: Option<CoreIdToken>,
  30. /// Token used to refresh the tokens if they expire
  31. pub refresh_token: Option<RefreshToken>,
  32. }
  33. pub fn email(
  34. client: CoreClient,
  35. id_token: CoreIdToken,
  36. nonce: Nonce,
  37. ) -> Result<String, ClaimsVerificationError> {
  38. match id_token.claims(&client.id_token_verifier(), &nonce) {
  39. Ok(claims) => Ok(claims.clone().email().unwrap().to_string()),
  40. Err(error) => Err(error),
  41. }
  42. }
  43. pub fn authorize_url(client: CoreClient) -> AuthRequest {
  44. let (authorize_url, _csrf_state, nonce) = client
  45. .authorize_url(
  46. AuthenticationFlow::<CoreResponseType>::AuthorizationCode,
  47. CsrfToken::new_random,
  48. Nonce::new_random,
  49. )
  50. .add_scope(openidconnect::Scope::new("email".to_string()))
  51. .add_scope(openidconnect::Scope::new("profile".to_string()))
  52. .url();
  53. AuthRequest {
  54. authorize_url: authorize_url.to_string(),
  55. nonce,
  56. }
  57. }
  58. pub async fn init_provider_metadata() -> Result<ProviderMetadataWithLogout, crate::errors::Error> {
  59. let issuer_url = IssuerUrl::new(crate::DIOXUS_FRONT_ISSUER_URL.to_string())?;
  60. Ok(ProviderMetadataWithLogout::discover_async(issuer_url, async_http_client).await?)
  61. }
  62. pub async fn init_oidc_client() -> Result<(ClientId, CoreClient), crate::errors::Error> {
  63. let client_id = ClientId::new(crate::DIOXUS_FRONT_CLIENT_ID.to_string());
  64. let provider_metadata = init_provider_metadata().await?;
  65. let client_secret = None;
  66. let redirect_url = RedirectUrl::new(format!("{}/login", crate::DIOXUS_FRONT_URL))?;
  67. Ok((
  68. client_id.clone(),
  69. CoreClient::from_provider_metadata(provider_metadata, client_id, client_secret)
  70. .set_redirect_uri(redirect_url),
  71. ))
  72. }
  73. ///TODO: Add pkce_pacifier
  74. pub async fn token_response(
  75. oidc_client: CoreClient,
  76. code: String,
  77. ) -> Result<CoreTokenResponse, crate::errors::Error> {
  78. // let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
  79. Ok(oidc_client
  80. .exchange_code(AuthorizationCode::new(code.clone()))
  81. // .set_pkce_verifier(pkce_verifier)
  82. .request_async(async_http_client)
  83. .await?)
  84. }
  85. pub async fn exchange_refresh_token(
  86. oidc_client: CoreClient,
  87. refresh_token: RefreshToken,
  88. ) -> Result<
  89. CoreTokenResponse,
  90. RequestTokenError<
  91. openidconnect::reqwest::Error<reqwest::Error>,
  92. StandardErrorResponse<CoreErrorResponseType>,
  93. >,
  94. > {
  95. oidc_client
  96. .exchange_refresh_token(&refresh_token)
  97. .request_async(async_http_client)
  98. .await
  99. }
  100. pub async fn log_out_url(id_token_hint: CoreIdToken) -> Result<Url, crate::errors::Error> {
  101. let provider_metadata = init_provider_metadata().await?;
  102. let end_session_url = provider_metadata
  103. .additional_metadata()
  104. .clone()
  105. .end_session_endpoint
  106. .unwrap();
  107. let logout_request: LogoutRequest = LogoutRequest::from(end_session_url);
  108. Ok(logout_request
  109. .set_client_id(ClientId::new(DIOXUS_FRONT_CLIENT_ID.to_string()))
  110. .set_id_token_hint(&id_token_hint)
  111. .http_get_url())
  112. }