Slotos/passport-reddit

Continual prompting of permission to allow

perry-mitchell opened this issue · 4 comments

Each time I log in with Reddit, I am asked to "Allow" my app to permanently login the user:

reddit_auth

My config:

    reddit: {
        clientID: "...",
        clientSecret: "...",
        callbackURL: "http://.../auth/reddit/callback"
    }

My setup:

    passport.use(new RedditStrategy(
        authMethods.reddit,
        function(accessToken, refreshToken, profile, done) {
            process.nextTick(function () {
                return done(null, profile);
            });
        }
    ));

        // ...
        app.get('/auth/reddit', function(req, res, next) {
            req.log({
                network: "reddit"
            }, "social login");
            req.session.state = crypto.randomBytes(32).toString('hex');
            passport.authenticate('reddit', {
                state: req.session.state,
                duration: 'permanent',
            })(req, res, next);
        });

        app.get('/auth/reddit/callback', function(req, res, next) {
            // Check for origin via state token 
            if (req.query.state == req.session.state) {
                passport.authenticate('reddit', {
                    successRedirect: loginSuccessRedirect,
                    failureRedirect: loginFailureRedirect
                })(req, res, next);
            } else {
                res.status(403).send('Forbidden');
            }
        });

If I logout and return to the Reddit auth, I'm prompted again - same with restarting the server.

Versions:

$ node -v; npm -v
v0.10.40
2.13.0

The server is node and express (latest) on Ubuntu 14.04.

Well, looks like reddit doesn't care if user have allowed you access in the past. In all honesty, I'm not sure I disagree with that decision.

Now, let me explain why I don't disagree with them. OAuth2 is first and foremost an authorisation protocol. Ability to authenticate your users is an inevitable side-effect, nothing more, nothing less. User authorises you to represent them in certain scopes of activity: read their data, post on their behalf etc. Granting such permissions just because you've been granted them in the past is insecure without control over your app's secret. It's not an insecurity that's easy to exploit, but it's insecurity nonetheless.

Anyways, duration parameter represents only one thing - duration of validity of the tokens that reddit returns you:

Access tokens are credentials used to access protected resources. An access token is a string representing an authorization issued to the client. The string is usually opaque to the client. Tokens represent specific scopes and durations of access, granted by the resource owner, and enforced by the resource server and authorization server.

When you request permanent duration, you get refresh token in addition to access token. How you persist this data, how you recognize the returning user, how you manage authentication in case of returning visitor is all up to you. Passport-reddit does not and ought not to do this for you, it's not the task is performs, albeit you can use it in conjunction with passport-local to achieve something like this.

I'm not sure how other OAuth2 providers handle this scenario (github is more lenient as far as I remember, but don't take my word for it), but reddit complies to RFC with the way they do it:

The authorization server validates the request to ensure that all required parameters are present and valid. If the request is valid, the authorization server authenticates the resource owner and obtains an authorization decision (by asking the resource owner or by establishing approval via other means).

You have three options:

  • Ask reddit developers to change this behavior, maybe by adding additional parameter in app settings on reddit.
  • Ask your users to create accounts on your site and use passport-reddit as a registration strategy.
  • Ignore the issue altogether.

Unfortunately there's not much I can do for you through passport-reddit, except ensuring that duration parameter get's to destination. Sorry.

That's a bit frustrating. I'm new to Passport, but I was expecting that each module would magically take care of the minor details of the authentication - however I do understand that it couldn't be that simple with every oauth endpoint.

From reading the Reddit spec on duration:

Indicates whether or not your app needs a permanent token. All bearer tokens expire after 1 hour. If you indicate you need permanent access to a user's account, you will additionally receive a refresh_token when acquiring the bearer token. You may use the refresh_token to acquire a new bearer token after your current token expires...

Would it not be best to manage the refreshing, in permanent mode, through the passport-reddit module?

I agree that using this for user registration on a site would still be completely suitable, but this issue does somewhat ruin the experience when using it as login mechanism (such as I am).

Would it not be best to manage the refreshing, in permanent mode, through the passport-reddit module?

Short answer, it's not that simple. Long answer, there exists a library for that, but do read a short answer and oauth2-refresh's issue #1. Even then there is no fault proof universal refresh strategy available. Any attempt to introduce a solution into this library will inevitably and justifiably upset someone. Thus I'm keeping it simple.

this issue does somewhat ruin the experience when using it as login mechanism (such as I am)

This is separate to refresh flow and has little in common with it. I can do nothing to make Reddit not ask your user to authorize your app over and over.

It's about your user logging out or clearing cookies, destroying all means for you or my library to identify them. You still possess tokens that let you act on behalf of user in some other system, but you have no data that would allow you to match your visitors to particular sets of tokens you received earlier. End of story.

You can initiate another authorization session in hope that a) remote system will handle repeated authorization in a transparent manner b) send you their internal id, that c) is immutable across requests.

Alternatively you can use initial authorization to populate your registration data and ask your new user to choose password or some other means of authorization. Thus removing three ifs from your workflow.


If you've selected "Web app" as your app type during app creation and reddit still requires explicit authorization every time, then I can do nothing short of creating a pull request to reddit/reddit, that is going to be rejected.

Ok, thanks for the in-depth replies, I appreciate it.

I will be in contact with Reddit in some manner regarding this, but in the mean time I probably won't be using Reddit as an authentication mechanism for precisely the point you stated - transparency. That being said, if we move to a registration-style auth system, I would definitely use passport-reddit in that context.

Cheers.