userp 0.0.4

Userp is a user account system inspired by Next Auth, with OAuth, password and email support, a ready-made Axum router with Askama templates, and more on the way!
Documentation
use super::custom::OAuthCustomProvider;
use crate::oauth::OAuthProviderUser;
use anyhow::Context;
use serde_json::Value;

pub struct SpotifyOAuthProvider;

impl SpotifyOAuthProvider {
    #[allow(clippy::new_ret_no_self)]
    pub fn new(
        client_id: impl Into<String>,
        client_secret: impl Into<String>,
    ) -> OAuthCustomProvider {
        OAuthCustomProvider::new_with_callback(
            "spotify",
            "Spotify",
            client_id,
            client_secret,
            "https://accounts.spotify.com/authorize",
            "https://accounts.spotify.com/api/token",
            &["user-read-email"],
            |access_token| async move {
                let client = reqwest::Client::new();

                let res = client
                    .get("https://api.spotify.com/v1/me")
                    .header("Accept", "application/json")
                    .bearer_auth(access_token)
                    .send()
                    .await?
                    .json::<Value>()
                    .await?;

                let id = res
                    .as_object()
                    .and_then(|obj| obj.get("id").and_then(|id| id.as_str()))
                    .context("Missing id")?
                    .to_string();

                let email = res
                    .as_object()
                    .and_then(|obj| obj.get("email").and_then(|id| id.as_str()))
                    .map(|name| name.to_string());

                let name = res
                    .as_object()
                    .and_then(|obj| obj.get("display_name").and_then(|id| id.as_str()))
                    .map(|name| name.to_string());

                Ok(OAuthProviderUser {
                    id,
                    email,
                    name,
                    email_verified: false,
                })
            },
        )
        .expect("Built in providers should work")
    }
}