0

Sorry for the simple question I just keep finding examples of "how to use them" not "when to use them"

Basically I have the code done for creating the refreshToken and destroying it

// Compare token in the database and create a new access token
Player.prototype.validateRefreshToken = function(username, refreshToken) {
    return new Promise(async (resolve, reject) => {
        try {
            let player = await this.col.findOneAsync({ username, refreshToken});
            if (player) {
                let token = jwt.sign(
                    {
                        id: player._id,
                        username: player.username, 
                        email: player.email,
                        roles: player.role || "user"
                    }, 
                    globals.jwtSecret,
                    {
                        expiresIn: "300"
                    }
                );

                return resolve(token);
            } else {
                return resolve(null);
            }
        } catch(err) {
            console.log("[ERROR]: There was an error trying to validateRefreshToken");
            console.log(err);
            return reject(err);
        }
    });
}

// Destroy users refreshToken by generating a new one and not delivering
// it to the client
Player.prototype.rejectToken = function (refreshToken) {
    return new Promise(async (resolve, reject) => {
        try {
            let player = await this.col.findOneAndUpdateAsync(
                { refreshToken },
                { $set: { refreshToken: randtoken.uid(256) },
            });
            if (player) {
                return resolve(true);
            } else {
                return resolve(false);
            }
        } catch(err) {
            console.log("[ERROR]: There was an error trying to rejectToken");
            console.log(err);
            return reject(err);
        }
    });
}

// API Routes
// Check Refresh Token
router.post("/token", async (ctx, next) => {
    let username = _.get(ctx.request.body, "username");
    let refreshToken = _.get(ctx.request.body, "refreshToken");

    if (refreshToken) {
        try {
            let token = ctx.models.player.validateRefreshToken(username, refreshToken);
            if (token) {
                ctx.body = { success: true, token };
            } else {
                ctx.body = { success: false, errors: ["You need to reauthenticate yourself their was an issue getting your refresh token"] };
            }
        } catch(err) {
            console.log(err);
            ctx.body = { success: false, errors: ["Internal Server Error"] };
        }
    } else {
        ctx.body = { success: false, errors: ["You are not authenticated"] };
    }
});


// Destroy refresh token
router.post("/token/reject", async (ctx, next) => {
    let refreshToken = _.get(ctx.request.body, "refreshToken");
    if (refreshToken) {
        try {
            let result = await ctx.models.player.rejectToken(refreshToken);
            if (result) {
                ctx.body = { success: true };
            } else {
                ctx.body = { success: false, errors: ["You are not authenticated"] };
            }
        } catch(err) {
            console.log(err);
            ctx.body = { success: false, errors: ["Internal Server Error"] };
        }
    }
});

But my problem is I don't know when I'm supposed to post to /token

E.g. somebody does a post request to their own profile /profile/me but gets a permission error, now what, how do I automate the /token

I hope this makes sense if it doesn't ask me for clarification

Datsik
  • 14,453
  • 14
  • 80
  • 121

1 Answers1

0

I'm going to assume your app is a mobile/desktop app - web apps do not generally need this support (although they could, I guess). Your app will do a HTTP request. When the token has expired, the HTTP request returns a 401 Unauthorized. Trap that.

In the code for the trap, check to see if your token has expired. If it has, refresh. If refresh doesn't work, do a full authentication. If the token has not expired, pass the 401 all the way back to your code because something else is going on.

In C#/Xamarin, you can use a delegating handler. In iOS or Android, you can wrap your original HTTP Client (NSURLSession or HttpClient) in a wrapper method that does the trap. In JavaScript / React Native / Cordova, you can wrap a fetch call that does the trap.

Adrian Hall
  • 7,990
  • 1
  • 18
  • 26
  • If you want an example in C#/Xamarin, see the code in my book: https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter2/realworld/#using-refresh-tokens – Adrian Hall May 07 '17 at 06:05
  • After you trap it and do the verification, is there a way to reissue the failed request? – Datsik May 07 '17 at 06:06
  • When you enter the wrapped section, you store a copy of the request. If you need to, you can then re-issue the request after the refresh. – Adrian Hall May 07 '17 at 14:46