Skip to content

Commit ee2826c

Browse files
authored
Remove send and sync (#109)
1 parent 3cfde64 commit ee2826c

File tree

5 files changed

+252
-19
lines changed

5 files changed

+252
-19
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ hex = "0.4"
3535
hmac = "0.8"
3636
uuid = { version = "0.8", features = ["v4"] }
3737
anyhow="1.0"
38+
tokio = { version = "0.2", features = ["full"] }

examples/github_async.rs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//!
2+
//! This example showcases the Github OAuth2 process for requesting access to the user's public repos and
3+
//! email address.
4+
//!
5+
//! Before running it, you'll need to generate your own Github OAuth2 credentials.
6+
//!
7+
//! In order to run the example call:
8+
//!
9+
//! ```sh
10+
//! GITHUB_CLIENT_ID=xxx GITHUB_CLIENT_SECRET=yyy cargo run --example github
11+
//! ```
12+
//!
13+
//! ...and follow the instructions.
14+
//!
15+
16+
use oauth2::basic::BasicClient;
17+
18+
// Alternatively, this can be `oauth2::curl::http_client` or a custom client.
19+
use oauth2::reqwest::async_http_client;
20+
use oauth2::{
21+
AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, RedirectUrl, Scope,
22+
TokenResponse, TokenUrl,
23+
};
24+
use std::env;
25+
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
26+
use tokio::net::TcpListener;
27+
use url::Url;
28+
29+
#[tokio::main]
30+
async fn main() {
31+
let github_client_id = ClientId::new(
32+
env::var("GITHUB_CLIENT_ID").expect("Missing the GITHUB_CLIENT_ID environment variable."),
33+
);
34+
let github_client_secret = ClientSecret::new(
35+
env::var("GITHUB_CLIENT_SECRET")
36+
.expect("Missing the GITHUB_CLIENT_SECRET environment variable."),
37+
);
38+
let auth_url = AuthUrl::new("https://github.com/login/oauth/authorize".to_string())
39+
.expect("Invalid authorization endpoint URL");
40+
let token_url = TokenUrl::new("https://github.com/login/oauth/access_token".to_string())
41+
.expect("Invalid token endpoint URL");
42+
43+
// Set up the config for the Github OAuth2 process.
44+
let client = BasicClient::new(
45+
github_client_id,
46+
Some(github_client_secret),
47+
auth_url,
48+
Some(token_url),
49+
)
50+
// This example will be running its own server at localhost:8080.
51+
// See below for the server implementation.
52+
.set_redirect_url(
53+
RedirectUrl::new("http://localhost:8080".to_string()).expect("Invalid redirect URL"),
54+
);
55+
56+
// Generate the authorization URL to which we'll redirect the user.
57+
let (authorize_url, csrf_state) = client
58+
.authorize_url(CsrfToken::new_random)
59+
// This example is requesting access to the user's public repos and email.
60+
.add_scope(Scope::new("public_repo".to_string()))
61+
.add_scope(Scope::new("user:email".to_string()))
62+
.url();
63+
64+
println!(
65+
"Open this URL in your browser:\n{}\n",
66+
authorize_url.to_string()
67+
);
68+
69+
// A very naive implementation of the redirect server.
70+
let mut listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
71+
loop {
72+
if let Ok((mut stream, _)) = listener.accept().await {
73+
let code;
74+
let state;
75+
{
76+
let mut reader = BufReader::new(&mut stream);
77+
78+
let mut request_line = String::new();
79+
reader.read_line(&mut request_line).await.unwrap();
80+
81+
let redirect_url = request_line.split_whitespace().nth(1).unwrap();
82+
let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap();
83+
84+
let code_pair = url
85+
.query_pairs()
86+
.find(|pair| {
87+
let &(ref key, _) = pair;
88+
key == "code"
89+
})
90+
.unwrap();
91+
92+
let (_, value) = code_pair;
93+
code = AuthorizationCode::new(value.into_owned());
94+
95+
let state_pair = url
96+
.query_pairs()
97+
.find(|pair| {
98+
let &(ref key, _) = pair;
99+
key == "state"
100+
})
101+
.unwrap();
102+
103+
let (_, value) = state_pair;
104+
state = CsrfToken::new(value.into_owned());
105+
}
106+
107+
let message = "Go back to your terminal :)";
108+
let response = format!(
109+
"HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}",
110+
message.len(),
111+
message
112+
);
113+
stream.write_all(response.as_bytes()).await.unwrap();
114+
115+
println!("Github returned the following code:\n{}\n", code.secret());
116+
println!(
117+
"Github returned the following state:\n{} (expected `{}`)\n",
118+
state.secret(),
119+
csrf_state.secret()
120+
);
121+
122+
// Exchange the code with a token.
123+
let token_res = client
124+
.exchange_code(code)
125+
.request_async(async_http_client)
126+
.await;
127+
128+
println!("Github returned the following token:\n{:?}\n", token_res);
129+
130+
if let Ok(token) = token_res {
131+
// NB: Github returns a single comma-separated "scope" parameter instead of multiple
132+
// space-separated scopes. Github-specific clients can parse this scope into
133+
// multiple scopes by splitting at the commas. Note that it's not safe for the
134+
// library to do this by default because RFC 6749 allows scopes to contain commas.
135+
let scopes = if let Some(scopes_vec) = token.scopes() {
136+
scopes_vec
137+
.iter()
138+
.map(|comma_separated| comma_separated.split(','))
139+
.flatten()
140+
.collect::<Vec<_>>()
141+
} else {
142+
Vec::new()
143+
};
144+
println!("Github returned the following scopes:\n{:?}\n", scopes);
145+
}
146+
147+
// The server will terminate itself after collecting the first code.
148+
break;
149+
}
150+
}
151+
}

src/lib.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@
5757
//! Synchronous HTTP clients should implement the following trait:
5858
//! ```ignore
5959
//! FnOnce(HttpRequest) -> Result<HttpResponse, RE>
60-
//! where RE: std::error::Error + Send + Sync + 'static
60+
//! where RE: std::error::Error + 'static
6161
//!
6262
//! Async/await HTTP clients should implement the following trait:
6363
//! ```ignore
6464
//! FnOnce(HttpRequest) -> F
6565
//! where
6666
//! F: Future<Output = Result<HttpResponse, RE>>,
67-
//! RE: std::error::Error + Send + Sync + 'static
67+
//! RE: std::error::Error + 'static
6868
//! ```
6969
//!
7070
//! # Getting started: Authorization Code Grant w/ PKCE
@@ -868,7 +868,7 @@ where
868868

869869
fn prepare_request<RE>(self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
870870
where
871-
RE: Error + Send + Sync + 'static,
871+
RE: Error + 'static,
872872
{
873873
let mut params = vec![
874874
("grant_type", "authorization_code"),
@@ -897,7 +897,7 @@ where
897897
pub fn request<F, RE>(self, http_client: F) -> Result<TR, RequestTokenError<RE, TE>>
898898
where
899899
F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
900-
RE: Error + Send + Sync + 'static,
900+
RE: Error + 'static,
901901
{
902902
http_client(self.prepare_request()?)
903903
.map_err(RequestTokenError::Request)
@@ -914,7 +914,7 @@ where
914914
where
915915
C: FnOnce(HttpRequest) -> F,
916916
F: Future<Output = Result<HttpResponse, RE>>,
917-
RE: Error + Send + Sync + 'static,
917+
RE: Error + 'static,
918918
{
919919
let http_request = self.prepare_request()?;
920920
let http_response = http_client(http_request)
@@ -989,7 +989,7 @@ where
989989
pub fn request<F, RE>(self, http_client: F) -> Result<TR, RequestTokenError<RE, TE>>
990990
where
991991
F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
992-
RE: Error + Send + Sync + 'static,
992+
RE: Error + 'static,
993993
{
994994
http_client(self.prepare_request()?)
995995
.map_err(RequestTokenError::Request)
@@ -1005,7 +1005,7 @@ where
10051005
where
10061006
C: FnOnce(HttpRequest) -> F,
10071007
F: Future<Output = Result<HttpResponse, RE>>,
1008-
RE: Error + Send + Sync + 'static,
1008+
RE: Error + 'static,
10091009
{
10101010
let http_request = self.prepare_request()?;
10111011
let http_response = http_client(http_request)
@@ -1016,7 +1016,7 @@ where
10161016

10171017
fn prepare_request<RE>(&self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
10181018
where
1019-
RE: Error + Send + Sync + 'static,
1019+
RE: Error + 'static,
10201020
{
10211021
Ok(token_request(
10221022
self.auth_type,
@@ -1101,7 +1101,7 @@ where
11011101
pub fn request<F, RE>(self, http_client: F) -> Result<TR, RequestTokenError<RE, TE>>
11021102
where
11031103
F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
1104-
RE: Error + Send + Sync + 'static,
1104+
RE: Error + 'static,
11051105
{
11061106
http_client(self.prepare_request()?)
11071107
.map_err(RequestTokenError::Request)
@@ -1118,7 +1118,7 @@ where
11181118
where
11191119
C: FnOnce(HttpRequest) -> F,
11201120
F: Future<Output = Result<HttpResponse, RE>>,
1121-
RE: Error + Send + Sync + 'static,
1121+
RE: Error + 'static,
11221122
{
11231123
let http_request = self.prepare_request()?;
11241124
let http_response = http_client(http_request)
@@ -1129,7 +1129,7 @@ where
11291129

11301130
fn prepare_request<RE>(&self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
11311131
where
1132-
RE: Error + Send + Sync + 'static,
1132+
RE: Error + 'static,
11331133
{
11341134
Ok(token_request(
11351135
self.auth_type,
@@ -1213,7 +1213,7 @@ where
12131213
pub fn request<F, RE>(self, http_client: F) -> Result<TR, RequestTokenError<RE, TE>>
12141214
where
12151215
F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
1216-
RE: Error + Send + Sync + 'static,
1216+
RE: Error + 'static,
12171217
{
12181218
http_client(self.prepare_request()?)
12191219
.map_err(RequestTokenError::Request)
@@ -1230,7 +1230,7 @@ where
12301230
where
12311231
C: FnOnce(HttpRequest) -> F,
12321232
F: Future<Output = Result<HttpResponse, RE>>,
1233-
RE: Error + Send + Sync + 'static,
1233+
RE: Error + 'static,
12341234
{
12351235
let http_request = self.prepare_request()?;
12361236
let http_response = http_client(http_request)
@@ -1241,7 +1241,7 @@ where
12411241

12421242
fn prepare_request<RE>(&self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
12431243
where
1244-
RE: Error + Send + Sync + 'static,
1244+
RE: Error + 'static,
12451245
{
12461246
Ok(token_request(
12471247
self.auth_type,
@@ -1356,7 +1356,7 @@ fn token_response<RE, TE, TR, TT>(
13561356
http_response: HttpResponse,
13571357
) -> Result<TR, RequestTokenError<RE, TE>>
13581358
where
1359-
RE: Error + Send + Sync + 'static,
1359+
RE: Error + 'static,
13601360
TE: ErrorResponse,
13611361
TR: TokenResponse<TT>,
13621362
TT: TokenType,
@@ -1627,7 +1627,7 @@ where
16271627
/// to support customization by clients, such as supporting interoperability with
16281628
/// non-standards-complaint OAuth2 providers
16291629
///
1630-
pub trait ErrorResponse: Debug + DeserializeOwned + Send + Serialize + Sync {}
1630+
pub trait ErrorResponse: Debug + DeserializeOwned + Serialize {}
16311631

16321632
///
16331633
/// Error types enum.
@@ -1636,7 +1636,7 @@ pub trait ErrorResponse: Debug + DeserializeOwned + Send + Serialize + Sync {}
16361636
/// this error type. This value must match the error type from the relevant OAuth 2.0 standards
16371637
/// (RFC 6749 or an extension).
16381638
///
1639-
pub trait ErrorResponseType: Debug + DeserializeOwned + Send + Serialize + Sync {}
1639+
pub trait ErrorResponseType: Debug + DeserializeOwned + Serialize {}
16401640

16411641
///
16421642
/// Error response returned by server after requesting an access token.
@@ -1738,7 +1738,7 @@ where
17381738
#[derive(Debug, thiserror::Error)]
17391739
pub enum RequestTokenError<RE, T>
17401740
where
1741-
RE: Error + Send + Sync + 'static,
1741+
RE: Error + 'static,
17421742
T: ErrorResponse + 'static,
17431743
{
17441744
///

src/reqwest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use thiserror::Error;
66
#[derive(Debug, Error)]
77
pub enum Error<T>
88
where
9-
T: std::error::Error + Send + Sync + 'static,
9+
T: std::error::Error + 'static,
1010
{
1111
/// Error returned by reqwest crate.
1212
#[error("request failed")]

0 commit comments

Comments
 (0)