oxide_auth/frontends/mod.rs
1//! A base for implementing front-ends.
2//!
3//! Front-ends are glue adapters from other http server crates to the interface exposed by
4//! individual methods offered in this crate. The exact usage of the front-end varies from
5//! implementation to implementation. Composability and usability are the main concerns for
6//! front-ends, full feature support is a secondary concern.
7//!
8//! ## Usage
9//!
10//! This only adds some base functionality for front-ends. The following front-ends have been
11//! implemented in separate crates:
12//!
13//! * `simple`: Implemented here, can be reused in other web servers.
14//! * `actix`: `oxide-auth-actix`
15//! * `iron`: `oxide-auth-iron`
16//! * `rouille`: `oxide-auth-rouille`
17//! * `rocket`: `oxide-auth-rocket`
18//!
19//! ## Guide to implementing a custom front-end
20//!
21//! All front-end implementations should start with two closely related traits: [`WebRequest`] and
22//! [`WebResponse`]. These central interfaces are used to interact with the libraries supported
23//! token flows (currently only authorization code grant).
24//!
25//! Lets step through those implementations one by one. As an example request type, let's pretend
26//! that the web interface consists of the following types:
27//!
28//! ```
29//! use oxide_auth::frontends::dev::*;
30//!
31//! struct ExampleRequest {
32//! /// The query part of the retrieved uri, conveniently pre-parsed.
33//! query: NormalizedParameter,
34//!
35//! /// The value of the authorization header if any was wet.
36//! authorization_header: Option<String>,
37//!
38//! /// A correctly interpreted version of the body of the request, only if its content type
39//! /// `application/x-form-urlencoded`
40//! urlbody: Option<NormalizedParameter>,
41//! }
42//!
43//! struct ExampleResponse {
44//! /// The http status code, 200 for OK
45//! status: u16,
46//!
47//! /// The Content or MIME type of the body
48//! content_type: Option<String>,
49//!
50//! /// The value of the `WWW-Authenticate` header if any
51//! www_authenticate: Option<String>,
52//!
53//! /// The value of the `Location` header if any
54//! location: Option<String>,
55//!
56//! /// The body sent
57//! body: Option<String>,
58//! }
59//! ```
60//! This is obviously incredibly simplified but will showcase the most valuable features of this
61//! library. Let's implement the required traits:
62//!
63//! ```
64//! # use std::collections::HashMap;
65//! use oxide_auth::frontends::dev::*;
66//! # struct ExampleRequest {
67//! # /// The query part of the retrieved uri, conveniently pre-parsed.
68//! # query: NormalizedParameter,
69//! #
70//! # /// The value of the authorization header if any was wet.
71//! # authorization_header: Option<String>,
72//! #
73//! # /// The body of the request, only if its content type was `application/x-form-urlencoded`
74//! # urlbody: Option<NormalizedParameter>,
75//! # }
76//! #
77//! # struct ExampleResponse {
78//! # /// The http status code, 200 for OK
79//! # status: u16,
80//! #
81//! # /// The Content or MIME type of the body
82//! # content_type: Option<String>,
83//! #
84//! # /// The value of the `WWW-Authenticate` header if any
85//! # www_authenticate: Option<String>,
86//! #
87//! # /// The value of the `Location` header if any
88//! # location: Option<String>,
89//! #
90//! # /// The body sent
91//! # body: Option<String>,
92//! # }
93//!
94//! impl WebRequest for ExampleRequest {
95//! // Declare the corresponding response type.
96//! type Response = ExampleResponse;
97//!
98//! // Our internal frontends error type is `OAuthError`
99//! type Error = OAuthError;
100//!
101//! fn query(&mut self) -> Result<Cow<QueryParameter + 'static>, OAuthError> {
102//! Ok(Cow::Borrowed(&self.query))
103//! }
104//!
105//! fn urlbody(&mut self) -> Result<Cow<QueryParameter + 'static>, OAuthError> {
106//! self.urlbody.as_ref()
107//! .map(|body| Cow::Borrowed(body as &QueryParameter))
108//! .ok_or(OAuthError::PrimitiveError)
109//! }
110//!
111//! fn authheader(&mut self) -> Result<Option<Cow<str>>, OAuthError> {
112//! // Borrow the data if it exists, else we had no header. No error cases.
113//! Ok(self.authorization_header.as_ref().map(|string| string.as_str().into()))
114//! }
115//! }
116//!
117//! impl WebResponse for ExampleResponse {
118//! // Redeclare our error type as in the request, those two must be the same.
119//! type Error = OAuthError;
120//!
121//! fn ok(&mut self) -> Result<(), OAuthError> {
122//! self.status = 200;
123//! self.www_authenticate = None;
124//! self.location = None;
125//! Ok(())
126//! }
127//!
128//! fn redirect(&mut self, target: Url) -> Result<(), OAuthError> {
129//! self.status = 302;
130//! self.www_authenticate = None;
131//! self.location = Some(target.into_string());
132//! Ok(())
133//! }
134//!
135//! fn client_error(&mut self) -> Result<(), OAuthError> {
136//! self.status = 400;
137//! self.www_authenticate = None;
138//! self.location = None;
139//! Ok(())
140//! }
141//!
142//! fn unauthorized(&mut self, www_authenticate: &str) -> Result<(), OAuthError> {
143//! self.status = 401;
144//! self.www_authenticate = Some(www_authenticate.to_string());
145//! self.location = None;
146//! Ok(())
147//! }
148//!
149//! fn body_text(&mut self, text: &str) -> Result<(), OAuthError> {
150//! self.body = Some(text.to_string());
151//! self.content_type = Some("text/plain".to_string());
152//! Ok(())
153//! }
154//!
155//! fn body_json(&mut self, json: &str) -> Result<(), OAuthError> {
156//! self.body = Some(json.to_string());
157//! self.content_type = Some("application/json".to_string());
158//! Ok(())
159//! }
160//! }
161//! ```
162//!
163//! And we're done, the library is fully usable. In fact, the implementation for `simple` is
164//! almost the same as what we just did with some minor extras. All that is missing is your web
165//! servers main loop to drive the thing and a look into the
166//! [`code_grant::endpoint::{AuthorizationFlow, GrantFlow, AccessFlow}`] which will explain the usage
167//! of the above traits in the context of the Authorization Code Grant.
168//!
169//! Of course, this style might not the intended way for some server libraries. In this case, you
170//! may want to provide additional wrappers. The `actix` front-end adds utilities for abstracting
171//! futures and actor messaging, for example.
172//!
173//! [`code_grant::endpoint::{AuthorizationFlow, GrantFlow, AccessFlow}`]: ../code_grant/endpoint/index.html
174//!
175
176pub mod simple;
177
178/// Simply a prelude useful for writing front-ends.
179pub mod dev {
180 pub use std::borrow::Cow;
181 pub use url::Url;
182 pub use crate::endpoint::{Endpoint, WebRequest, WebResponse};
183 pub use crate::endpoint::{OAuthError, OwnerSolicitor, NormalizedParameter, QueryParameter};
184}