steam_auth/lib.rs
1//! Allows you to implement a 'login with steam' feature on your website.
2//!
3//! ## Usage
4//!
5//! The easiest way to use this crate is with the `reqwest-09x` feature which allows the library to
6//! make HTTP requests on your behalf. Otherwise, you will need to do that manually.
7//!
8//! Using the `reqwest-09x` feature:
9//! ```rust
10//! # use steam_auth::{Redirector, Verifier};
11//! # fn main() {
12//! // First, create a redirector
13//! let redirector = Redirector::new("http://localhost:8080", "/callback").unwrap();
14//!
15//! // When a user wants to log in with steam, (e.g when they land on the `/login` route),
16//! // redirect them to this URL:
17//! let redirect_url = redirector.url();
18//!
19//! // Once they've finished authenticating, they will be returned to `/callback` with some data in
20//! // the query string that needs to be parsed and then verified by sending an HTTP request to the steam
21//! // servers.
22//! # let querystring = "openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=id_res&openid.op_endpoint=https%3A%2F%2Fsteamcommunity.com%2Fopenid%2Flogin&openid.claimed_id=https%3A%2F%2Fsteamcommunity.com%2Fopenid%2Fid%2F92345666790633291&openid.identity=https%3A%2F%2Fsteamcommunity.com%2Fopenid%2Fid%2F12333456789000000&openid.return_to=http%3A%2F%2Flocalhost%3A8080%2Fcallback&openid.response_nonce=2019-06-15T00%3A36%3A00Z7nVIS5lDAcZe%2FT0gT4%2BQNQyexyA%3D&openid.assoc_handle=1234567890&openid.signed=signed%2Cop_endpoint%2Cclaimed_id%2Cidentity%2Creturn_to%2Cresponse_nonce%2Cassoc_handle&openid.sig=BK0zC%2F%2FKzERs7N%2BNlDO0aL06%2BBA%3D";
23//! match Verifier::make_verify_request(&reqwest::Client::new(), querystring) {
24//! Ok(steam_id) => println!("Successfully logged in user with steam ID 64 {}", steam_id),
25//! Err(e) => eprintln!("There was an error authenticating: {}", e),
26//! }
27//! # }
28//! ```
29//!
30//! There is an asynchronous variant: `Verifier::make_verify_request_async` which returns a
31//! future. You can also deserialize the data into a `SteamLoginData` struct and construct a
32//! `Verifier` from that if it is more convenient.
33//!
34//! If you don't want to depend on request, you'll need to send the HTTP request yourself. See the
35//! [example server](https://github.com/64/steam-auth/blob/master/examples/server.rs) and the
36//! `Verifier` documentation for more details on how this can be done.
37
38#[macro_use]
39extern crate serde_derive;
40#[macro_use]
41extern crate failure;
42
43mod redirector;
44mod verifier;
45
46pub use redirector::Redirector;
47pub use verifier::SteamLoginData;
48pub use verifier::Verifier;
49
50pub(crate) const STEAM_URL: &str = "https://steamcommunity.com/openid/login";
51
52#[derive(Debug, Fail)]
53pub enum Error {
54 #[fail(display = "bad site or return url: {}", _0)]
55 /// The site or return URL was incorrect
56 BadUrl(url::ParseError),
57 #[fail(display = "failed to parse SteamAuthRequest (please file bug): {}", _0)]
58 /// Internal error serializing the query string - should never happen.
59 ParseQueryString(serde_urlencoded::ser::Error),
60 #[fail(display = "authentication failed")]
61 /// The authentication failed because the data provided to the callback was invalid
62 AuthenticationFailed,
63 #[fail(display = "failed to parse steam id")]
64 /// There was an error parsing the Steam ID returned to the callback
65 ParseSteamId,
66 #[fail(display = "failed to build HTTP request or response: {}", _0)]
67 BuildHttpStruct(http::Error),
68 #[fail(display = "error serializing url encoded data: {}", _0)]
69 Serialize(serde_urlencoded::ser::Error),
70 #[fail(display = "error deserializing url encoded data: {}", _0)]
71 Deserialize(serde_urlencoded::de::Error),
72 #[fail(display = "reqwest error: {}", _0)]
73 #[cfg(feature = "reqwest-09x")]
74 /// There was an error during the verify request
75 Reqwest(reqwest::Error),
76}
77
78#[cfg(feature = "reqwest-0_9")]
79pub fn verify_response_async(
80 client: &reqwest::r#async::Client,
81 mut form: SteamAuthResponse,
82) -> impl futures::Future<Item = u64, Error = Error> {
83 client
84 .post(STEAM_URL)
85 .form(&form)
86 .send()
87 .map_err(Error::Reqwest)
88 .and_then(|res| res.into_body().concat2().map_err(Error::Reqwest))
89 .and_then(move |body| {
90 let s = std::str::from_utf8(&body)
91 .map_err(|_| Error::AuthenticationFailed)?
92 .to_owned();
93
94 parse_verify_response(&form.claimed_id, s)
95 })
96}