Giter Club home page Giter Club logo

rocket_oauth2's People

Contributors

carlschwan avatar cbzehner avatar fenhl avatar hcrohland avatar jarviscraft avatar jebrosen avatar kije avatar legoktm avatar mautamu avatar sithsiri avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

rocket_oauth2's Issues

Multiple redirect URIs?

Is it possible to use different redirect URLs? I'd like to have OAuth on web and mobile platforms all be redirected through my backend, however, they require different redirect URIs.

Support revoking tokens

So in my application I want to be able to revoke user tokens when they log out. While I could just delete the tokens this does leave some potential security issues and leaves my app onto their authorized apps page.

I don't know much about how rfc:s and such work but revoking seems to be described in RFC7009 the process is also described in the Reddit api docs.

Now I don't know if this stuff is in spec or not and I don't know how well it's supported on other services but I would appreciate having revoking as a feature.

Plans for Rocket v0.5

๐Ÿ‘‹ Hi Jeb,

Just wondering - what are the plans for this crate with the upcoming Rocket v0.5 release (which I'm sure is keeping you plenty busy ๐Ÿ˜…)?

I've used this with v0.4 and really appreciated the ergonomics of it - I'd like to use it with a new project based on the v0.5-rc1 branch of Rocket but am not sure where to get started.

If you're interested, I'd be happy to help fix some of the type errors that come up but there's probably some larger changes needed with the ability to use async (does hyper_sync_rustls still make sense?) and the move to Figment.

Update to support rocket =0.5.0-rc.4

First off, thanks for this great crate! :)

Rocket 0.5.0-rc.4 was just released with several breaking changes.

Relevant:

  • Outcome::Failure was renamed to Outcome::Error.
  • change to Cookie::build
error[E0599]: no variant or associated item named `Failure` found for enum `Outcome` in the current scope
   --> /.cargo/registry/src/index.crates.io-6f17d22bba15001f/rocket_oauth2-0.5.0-rc.2/src/lib.rs:431:33
    |
431 |                 return Outcome::Failure((
    |                                 ^^^^^^^ variant or associated item not found in `Outcome<_, (Status, _), Status>`

error[E0599]: no variant or associated item named `Failure` found for enum `Outcome` in the current scope
   --> /.cargo/registry/src/index.crates.io-6f17d22bba15001f/rocket_oauth2-0.5.0-rc.2/src/lib.rs:453:33
    |
453 |                 return Outcome::Failure((
    |                                 ^^^^^^^ variant or associated item not found in `Outcome<_, (Status, _), Status>`

error[E0599]: no variant or associated item named `Failure` found for enum `Outcome` in the current scope
   --> /.cargo/registry/src/index.crates.io-6f17d22bba15001f/rocket_oauth2-0.5.0-rc.2/src/lib.rs:478:37
    |
478 |                     return Outcome::Failure((
    |                                     ^^^^^^^ variant or associated item not found in `Outcome<_, (Status, _), Status>`

error[E0599]: no variant or associated item named `Failure` found for enum `Outcome` in the current scope
   --> /.cargo/registry/src/index.crates.io-6f17d22bba15001f/rocket_oauth2-0.5.0-rc.2/src/lib.rs:511:26
    |
511 |                 Outcome::Failure((Status::BadRequest, e))
    |                          ^^^^^^^ variant or associated item not found in `Outcome<_, (Status, _), Status>`

error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> /.cargo/registry/src/index.crates.io-6f17d22bba15001f/rocket_oauth2-0.5.0-rc.2/src/lib.rs:710:13
    |
710 |             Cookie::build(STATE_COOKIE_NAME, state)
    |             ^^^^^^^^^^^^^                  -------
    |                                            | |
    |                                            | unexpected argument of type `std::string::String`
    |                                            help: remove the extra argument
    |
note: associated function defined here
   --> /.cargo/registry/src/index.crates.io-6f17d22bba15001f/cookie-0.18.0/src/lib.rs:324:12
    |
324 |     pub fn build<C: Into<Cookie<'c>>>(base: C) -> CookieBuilder<'c> {
    |        

Trying to use this against the MS Azure endpoints results in a DeserializationError

Setting this up against MS (for use against the Azure oauth2 endpoints in AuthorizationCode workflow) doesn't like the response back from the token endpoint:

Error: Token exchange failed: Error { kind: DeserializationError(Error("invalid type: string "3600", expected i32", line: 1, column: 62)) }

I think this is coming from the serde deserialize call at the end of the token exchange handler, but I can't see the response back from the endpoint to see what data it's choking on.

For reference, I've set this out as a custom Provider using the Table notation (bit of digging into the code led me to that approach):

[global.oauth.azure]
provider = { auth_uri = "https://login.microsoftonline.com/common/oauth2/authorize", token_uri = "https://login.microsoftonline.com/common/oauth2/token" }
redirect_uri = "https://localhost:8000/user/auth"
client_id = "<redacted>"
client_secret = "<redacted>"

I've then attached the fairing to my Rocket as so:

        .attach(OAuth2::fairing(HyperSyncRustlsAdapter, login_azure_callback, "azure", "/user/auth", Some(("/user/login", vec!["user:read".to_string()]))))

where my login_azure_callback is:

pub fn login_azure_callback(request: &Request, token: TokenResponse) -> Result<Redirect, Box<::std::error::Error>> {
    let mut cookies = request.guard::<Cookies>().expect("Cookies");

    cookies.add_private(
        Cookie::build("token", token.access_token)
            .same_site(SameSite::Lax)
            .finish()
    );
    Ok(Redirect::to("/"))
}

This works, in as much as obtaining the auth code works, I get the MS oauth flow, but the redirect back results in a 400 BadRequest and the error above.

Handle 400 errors from the authorization server

I was wondering if there is any way to handle custom status codes other than 200.

I get the redirect to callback_url with something like this

https://b5f6-45-251-234-73.ngrok.io/auth/instagram?code=AQBwRfNKQFHiv-X6m0-O8M9iLDrM-uVMwDcjYSyLRzIUeXylPVhu4V7qIZcEuT37yi21QtBjhiuvBAdi1g2jo_ddS68I3bIIcEddezdbsDo8GOLrxVVxupQpPKH5Fz6WaxGEbkzfUu9nhdiLy5Pa5Ri1sFm1GksUmK9jWRfHPfS73jgiL0jO45w91EQgR5kui3vHzchklRx-H_xDh9-YIb8i9ScdJsYXJZydBNZ5s4V9cA&state=3INTGxYIbi5lBu9ROTtUXw#_

but with 400 bad request.

So my question is, Is there any simple way to handle the 400 status code ?

How to implement refresh token exchange

Hi Jeb,

I am wondering how to best implement the refresh token exchange in rocket_oauth2.
As a relative newcomer to rocket I am not sure that I would come up with a good solution.
But here are my thoughts:

Implementing the exchange function is trivial by adding a token type parameter to Adapter::exchange_token. But how to access it from a request is the question: AFAIU you cannot access a fairing from a request. So we would need to register another object as managed state!?! Does not look very elegant to me.

Do you have any ideas?

Cheers,
Christoph

Callback fails to run if request parameters are in the wrong order

The parameters to the callback in the examples and docs look like this:

#[get("/auth/microsoft")]
fn microsoft_callback(
    token: TokenResponse<MicrosoftUserInfo>,
    mut cookies: Cookies<'_>,
) -> Result<Redirect, Debug<Error>> {
    ...
}

I was playing around just now and for some reason swapped the two parameters so that the signature looked like this:

#[get("/auth/microsoft")]
fn microsoft_callback(
    mut cookies: Cookies<'_>,
    token: TokenResponse<MicrosoftUserInfo>,
) -> Result<Redirect, Debug<Error>> {
    ...
}

And when that route is hit, the following error is shown in the logs:

    => Matched: GET /auth/microsoft (microsoft_callback)
    => Error: Multiple `Cookies` instances are active at once.
    => An instance of `Cookies` must be dropped before another can be retrieved.
    => Warning: The retrieved `Cookies` instance will be empty.
Warning: The OAuth2 state returned from the server did not match the stored state.
    => Outcome: Failure
    => Warning: Responding with 400 Bad Request catcher.
    => Response succeeded.

This presumably makes sense given a bit of knowledge of Rocket's request handling, since TokenResponse's FromRequest impl needs mutable access the cookies and they're already borrowed mutably by mut cookies, but it's a bit surprising - probably nothing that documentation can't manage.

DeserializationError when using Twitch as a provider.

When using Twitch as a provider, I get the following error:

Token exchange failed: Error { kind: DeserializationError(Error("invalid type: sequence, expected a string", line: 1, column: 146)) }.

Example data returned from Twitch:

{
  "access_token": "0123456789abcdefghijABCDEFGHIJ",
  "refresh_token": "eyJfaWQmNzMtNGCJ9%6VFV5LNrZFUj8oU231/3Aj",
  "expires_in": 3600,
  "scope": ["viewing_activity_read"],
  "token_type": "bearer"
}

I suspect it may be Twitch returning an array of scopes rather than a space-separated string.

Custom providers, using issuer URL

It'd be nice to pass a single URL to rocket_oauth2 to discover the token and redirection endpoints lazily. The even more general use case is complete OpenID Connect Discovery via webfinger (not covered here).

I'd expect my application to work like this:

This doesn't appear to be possible right now, because the Provider needs to be passed into rocket_oauth2 and be initialized on startup.

Maybe a solution would be to implement the Provider as a trait rather than a struct, so that the URLs could be fetched lazily if need be - auth_uri and token_uri are only needed upon the first request anyways.
This way, I could pass a custom Provider implementation that fetches the OP metadata on demand.

Cheers,
Uwe

Do not check token-type.

I'm trying to implement VK OAuth2, but their API responds with JSON like this (idk why, they even put a link to OAuth specs):

{
  "access_token": "533bacf01e11f55b536a565b57531ac114461ae8736d6506a3",
  "expires_in": 43200,
  "user_id": 66748
}

So I need a way to get an access token, but I get this error right now:

Err(
    Error {
        kind: ExchangeFailure,
        source: Some(
            "TokenResponse token_type was missing or not a string",
        ),
    },
)

How can get around with this?

Reddit configuration not actually working

By default rocket_oauth2 doesn't work with the reddit config it provides. This is because on the exchange_code function reddit expects the client id and secret to be provided using a Authorization header. Reddit details the requirements here but basically using the default code reddit will just return a 401 because the Authorization header isn't provided

I was able to get reddit logon working by replacing lines 76-85 in hyper_sync_rustls_adapter.rs with

        //ser.append_pair("client_id", config.client_id());
        //ser.append_pair("client_secret", config.client_secret());

        let req_str = ser.finish();

        let request = client
            .post(config.provider().token_uri().as_ref())
            .header(Accept::json())
            .header(ContentType::form_url_encoded())
            .header(Authorization(
                Basic {
                    username: config.client_id().to_owned(),
                    password: Some(config.client_secret().to_owned()),
                }
            ))
            .body(&req_str);

also its impossible to get an refresh token with reddit as its api requires you to tell it during authorization whenever you want a temporary or permanent token using a duration parameter in the request. I was also able to workaround this by just hardcoding the authorization request to set the duration. I think this wouldn't be a problem if issue #13 got resolved as then duration could be sent using an custom parameter.

also unrelated the version of rocket_sync_rustls should probably be updated as it uses an old version of rustls. This caused problems for me as i use another lib that uses a newer version of rustls and I could not compile as two versions of ring-asm were required and as ring-asm is a native library it can only have one compiled version. I was able to fix this by just changing the cargo.toml to use version =0.3.0-rc.17 instead of =0.3.0-rc.4

Docs: Add example with Custom Provider

Hi, I've been using rocket_oauth2 on the side to try and implement a Slackbot with some basic functionality. It took me quite a while to figure out how specify a custom provider so I'd like to contribute back an example of how to set one up.

I already put up a draft pull request #11 based on the Slack integration I set up, but ran into some issues with the basic.identity scope. I'd appreciate any insights on how to fix this. If it doesn't seem reasonable to fix (I don't expect anyone here to be supporting specific OAuth2 implementations!) would you mind suggesting another API we could implement to showcase how to use custom providers?

My initial goal was to provide an example as similar as possible to the existing examples/user_info_hyper_sync_rustls so it readers would have an easy time spotting differences.

How secure is this?

Sorry, I am rather new to OAuth and especially integrating it into Rust.

I am using Microsoft and pulling the email address from the microsoft account in /auth/microsoft into a cookie as follows:

    cookies.add_private(
        Cookie::build(("email", user_info.email))
            .same_site(SameSite::Lax)
            .build(),

I noticed that there is a cookie on the client side.

Imagine I implement another route as follows:

#[get("/other")]
async fn other(user: User) -> String {
    user.email
}

Also imagine it does something sensitive rather than returning the email address. Apart from stealing a legitimate token/email cookie. Is this secure? Is there no way someone can just impersonate someone else or simply change there email address value without obtaining a legitimate token.

E.g., can a user simply change their email cookie to some random string with a special encoding or is it secure?

My data on the server-side will most likely be tied to the users email and so I do not want the user to be able to change this without obtaining a valid token/cookie (I am currently ignoring cookie grabbing with XSS at the moment as it should not be a problem for me)

How to implement dynamic redirect_uris

Hi there,

I'm currently toying around with rocket/_oauth2 and wondering about a very common auth scenario:

User...

  • logs in to webapp
  • either lets their session expire or bookmarks current route/URI
  • user comes back to URI without being logged in
  • user sees login prompt and logs in again
    -> expectation: user ends up at the same URI as before

After the last step, the expectation is that the user will return to the same route that he/she was at before (the one he/she bookmarked or let the session expire on).

OAuth2 supports this via the ?state=.., which rocket_oauth2 happily fills with its own state as it appears.

So how would I implement the above scenario?

Cheers,

Uwe

scope parameter is not returned by token exchange

Hi Jeb,

just started using your crate.

Your code assumes that the scope parameter is returned by the token exchange.
But the RFC states that it will be transmitted with the authorization callback.
So TokenResponse.scope is always none.

I am willing to work on a patch but I am unsure how to do it:

  • Fill TokenResponse.scope in fn handle or...
  • Change the callback interface to have an explicit parameter and remove the scope from struct TokenResponse.

The first one should be easy. But this field does not really belong in TokenResponse. And if we wanna add Refresh token support it would not be able to fill the scope field.

What do you think?

Cheers,
Christoph

Verify token validity

(Sorry, this is more a question than an issue).

Thanks for your work! Pretty useful :)

What would be a recommended approach to validate the access_token in api calls?

Feature: Make redirect_uri optional

Hi, as far as I can see the redirect_uri seems to be required in any case: https://github.com/jebrosen/rocket_oauth2/blob/master/src/config.rs#L13

Now in the scenario I'm using this library, which is only the token exchange, in a server-to-server scenario, providing the redirect_uri is not required (also see github's docs: https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#parameters-1).

It would be nice if this library allowed me to omit this parameter.

Cookie `rocket_oauth2_state` with `secure` flag

In https://github.com/jebrosen/rocket_oauth2/blob/0.5.0-rc.1/src/lib.rs#L693 the rocket_oauth2_state cookie is set. By default, Rocket's add_private securely configures cookies with httponly(true), however the secure flag is not set. Would it be possible to add a possibility to set the secure flag on this cookie? Either automatically when a secure connection is used (not sure if this is possible), or somehow in the configuration? Or just make it the default for production builds?

I am also considering to suggest this on Rocket as a default instead, as I think it would better to use secure defaults (at the very least for production builds).

Allow extending of authorization endpoint parameters.

(Split off from #11 (comment))

Some providers require or support additional parameters to be specified in the redirect request. One example is Slack, which has a second user_scope= parameter to specify scopes for the impersonated user in addition to the standard scope= which applies to the bot user.

This should be possible to do today by retrieving OAuth2<C> from managed state, calling OAuth2<C>::get_redirect(), and then manually mangling the Redirect URI. This is an unsavory option.

Perhaps it should be easier to add custom request parameters; something similar was done for TokenResponse (see #9 (comment)) to allow access to the exact data returned by the server. One option might be OAuth2<C>::get_redirect_custom(&self, cookies: &mut Cookies<'_>, scopes: &[&str], params: Params). Params would likely be an iterator of key-value pairs.

I would appreciate any further examples of providers that would benefit or require this functionality.

EDIT(2020-08-20): Removed mention of the automatically-generated login route, which was removed in 0.3.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.