Skip to content

Commit

Permalink
Added OTP verification
Browse files Browse the repository at this point in the history
No test added (yet).
  • Loading branch information
Eric Biggs committed Sep 14, 2024
1 parent c1715be commit 8af6ce6
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ It should be noted there are, and will likely always be, differences to the [JS

This crate doesn't use pascalCase. Instead we use the snake_case convention.

Any features which are currently deprecated in the [JS client](https://github.com/supabase/gotrue-js) will not be supported.

## Usage (Won't be updated until 1.0.0)

```rust
Expand Down
57 changes: 51 additions & 6 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
Provider, RequestMagicLinkPayload, Session, SignInWithEmailAndPasswordPayload,
SignInWithIdTokenCredentials, SignInWithPhoneAndPasswordPayload,
SignUpWithEmailAndPasswordPayload, SignUpWithPhoneAndPasswordPayload, UpdateUserPayload,
User,
User, VerifyOtpParams,
},
};

Expand All @@ -30,17 +30,38 @@ pub struct AuthClient {

impl AuthClient {
/// Create a new AuthClient
pub fn new(project_url: &str, api_key: &str, jwt_secret: &str) -> Self {
pub fn new(
project_url: impl Into<String>,
api_key: impl Into<String>,
jwt_secret: impl Into<String>,
) -> Self {
let client = Client::new();

AuthClient {
client,
project_url: project_url.to_string(),
api_key: api_key.to_string(),
jwt_secret: jwt_secret.to_string(),
project_url: project_url.into(),
api_key: api_key.into(),
jwt_secret: jwt_secret.into(),
}
}

/// Create a new AuthClient from environment variables
/// Requires `SUPABASE_URL`, `SUPABASE_API_KEY`, and `SUPABASE_JWT_SECRET` environment variables
pub fn new_from_env() -> Result<AuthClient, Error> {
let client = Client::new();

let project_url = env::var("SUPABASE_URL")?;
let api_key = env::var("SUPABASE_API_KEY")?;
let jwt_secret = env::var("SUPABASE_JWT_SECRET")?;

Ok(AuthClient {
client,
project_url: project_url.into(),
api_key: api_key.into(),
jwt_secret: jwt_secret.into(),
})
}

pub async fn sign_in_with_email_and_password<S: Into<String>>(
&self,
email: S,
Expand All @@ -54,7 +75,6 @@ impl AuthClient {
let mut headers = header::HeaderMap::new();
headers.insert("Content-Type", "application/json".parse().unwrap());
headers.insert("apikey", self.api_key.parse().unwrap());

let body = serde_json::to_string(&payload)?;

let response = self
Expand Down Expand Up @@ -356,4 +376,29 @@ impl AuthClient {

Ok(serde_json::from_str(&response)?)
}

pub async fn verify_otp(&self, params: VerifyOtpParams) -> Result<Session, Error> {
let mut headers = HeaderMap::new();
headers.insert("apikey", self.api_key.parse()?);
headers.insert(CONTENT_TYPE, "application/json".parse()?);

let body = match params {
VerifyOtpParams::Mobile(params) => serde_json::to_string(&params)?,
VerifyOtpParams::Email(params) => serde_json::to_string(&params)?,
VerifyOtpParams::TokenHash(params) => serde_json::to_string(&params)?,
};

let client = Client::new();

let response = client
.post(&format!("{}/verify", self.project_url))
.headers(headers)
.body(body)
.send()
.await?
.text()
.await?;

Ok(serde_json::from_str(&response)?)
}
}
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::env;

use thiserror::Error;

#[derive(Debug, Error)]
Expand All @@ -22,4 +24,6 @@ pub enum Error {
ParseError(#[from] serde_json::Error),
#[error("Header Value is Invalid")]
InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
#[error("Environment Variable Unreadable")]
InvalidEnvironmentVariable(#[from] env::VarError),
}
69 changes: 69 additions & 0 deletions src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,75 @@ pub struct UpdateUserPayload {
pub(crate) data: Option<serde_json::Value>,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum VerifyOtpParams {
Mobile(VerifyMobileOtpParams),
Email(VerifyEmailOtpParams),
TokenHash(VerifyTokenHashParams),
}

#[derive(Debug, Serialize, Deserialize)]
pub struct VerifyMobileOtpParams {
/// The user's phone number.
pub phone: String,
/// The otp sent to the user's phone number.
pub token: String,
/// The user's verification type.
#[serde(rename = "type")]
pub otp_type: MobileOtpType,
/// Optional parameters
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<VerifyOtpOptions>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct VerifyEmailOtpParams {
/// The user's phone number.
pub email: String,
/// The otp sent to the user's phone number.
pub token: String,
/// The user's verification type.
#[serde(rename = "type")]
pub otp_type: MobileOtpType,
/// Optional parameters
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<VerifyOtpOptions>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct VerifyTokenHashParams {
/// The user's phone number.
pub token_hash: String,
/// The user's verification type.
#[serde(rename = "type")]
pub otp_type: MobileOtpType,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EmailOtpType {
Signup,
Invite,
Magiclink,
Recovery,
EmailChange,
Email,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MobileOtpType {
Sms,
PhoneChange,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct VerifyOtpOptions {
/// A URL to send the user to after they are confirmed.
#[serde(skip_serializing_if = "Option::is_none")]
pub redirect_to: Option<String>,
}

#[derive(Debug, Serialize)]
pub enum Provider {
Apple,
Expand Down
8 changes: 2 additions & 6 deletions tests/client_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ use supabase_auth::client::AuthClient;

#[tokio::test]
async fn create_client_test_valid() {
let test_project_url = env::var("SUPABASE_URL").unwrap();
let test_api_key = env::var("SUPABASE_API_KEY").unwrap();
let test_jwt_secret = env::var("SUPABASE_JWT_SECRET").unwrap();

let auth_client = AuthClient::new(&test_project_url, &test_api_key, &test_jwt_secret);
let auth_client = AuthClient::new_from_env().unwrap();

assert!(auth_client.project_url == test_project_url)
assert!(auth_client.project_url == env::var("SUPABASE_URL").unwrap())
}

#[tokio::test]
Expand Down

0 comments on commit 8af6ce6

Please sign in to comment.