oxide-auth 0.4.5

A OAuth2 server library, for actix, rocket, iron or other libraries, featuring a set of configurable and pluggable backends.
Documentation
extern crate rocket;

#[path = "generic.rs"]
mod generic;

use self::generic::{Client, ClientConfig, ClientError};

use rocket::{Rocket, State};
use rocket::fairing::{Fairing, Info, Kind};
use rocket::http::Status;
use rocket::response::{Redirect, content::Html, status::Custom};

pub use self::generic::consent_page_html;
pub struct ClientFairing;

impl Fairing for ClientFairing {
    fn info(&self) -> Info {
        Info {
            name: "Simple oauth client implementation",
            kind: Kind::Attach,
        }
    }

    fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
        let config = ClientConfig {
            client_id: "LocalClient".into(),
            protected_url: "http://localhost:8000/".into(),
            token_url: "http://localhost:8000/token".into(),
            refresh_url: "http://localhost:8000/refresh".into(),
            redirect_uri: "http://localhost:8000/clientside/endpoint".into(),
        };
        Ok(rocket
            .manage(Client::new(config))
            .mount("/clientside", routes![oauth_endpoint, client_view, client_debug, refresh]))
    }
}

#[get("/endpoint?<code>&<error>")]
fn oauth_endpoint<'r>(code: Option<String>, error: Option<String>, state: State<Client>)
    -> Result<Redirect, Custom<String>> 
{
    if let Some(error) = error {
        return Err(Custom(Status::InternalServerError, 
            format!("Error during owner authorization: {:?}", error)))
    }

    let code = code
        .ok_or_else(|| Custom(Status::BadRequest, 
            "Endpoint hit without an authorization code".into()))?;
    state.authorize(&code)
        .map_err(internal_error)?;

    Ok(Redirect::found("/clientside"))
}

#[get("/")]
fn client_view(state: State<Client>) -> Result<Html<String>, Custom<String>> {
    let protected_page = state
        .retrieve_protected_page()
        .map_err(internal_error)?;

    let display_page = format!(
        "<html><style>
            aside{{overflow: auto; word-break: keep-all; white-space: nowrap}}
            main{{text-align: center}}
            main>aside,main>article{{margin: auto; text-align: left; border: 1px solid black; width: 50%}}
        </style>
        <main>
        Used token <aside style>{}</aside> to access
        <a href=\"http://localhost:8000/\">http://localhost:8000/</a>.
        Its contents are:
        <article>{:?}</article>
        <form action=\"/clientside/refresh\" method=\"post\"><button>Refresh token</button></form>
        </main></html>", state.as_html(), protected_page);

    Ok(Html(display_page))
}

#[post("/refresh")]
fn refresh(state: State<Client>) -> Result<Redirect, Custom<String>> {
    state.refresh()
        .map_err(internal_error)
        .map(|()| Redirect::found("/clientside"))
}

#[get("/debug")]
fn client_debug(state: State<Client>) -> Html<String> {
    Html(state.as_html())
}

fn internal_error(err: ClientError) -> Custom<String> {
    Custom(Status::InternalServerError, err.to_string())
}