How do I refresh discord Oauth2 access token using refresh token?

Viewed 2172

I am using discord Oauth2 on my website.

This is my code:

let params = new URLSearchParams(window.location.search);
let info = document.getElementById('info');

if (params.has('code')) {
    let code = params.get('code');

    fetch('https://discord.com/api/oauth2/token', {
        method  : 'POST',
        headers : {
            'Content-Type' : 'application/x-www-form-urlencoded'
        },
        body    : new URLSearchParams({
            client_id     : '################',
            client_secret : '######################',
            grant_type    : 'authorization_code',
            code          : code,
            redirect_uri  : 'http://127.0.0.1:5501/public/'
        })
    })
        .then((res) => res.json())
        .then(function(res) {
            setInterval(() => {
                fetch('https://discord.com/api/oauth2/token/revoke', {
                    method  : 'POST',
                    headers : {
                        'Content-Type' : 'application/x-www-form-urlencoded'
                    },
                    body    : new URLSearchParams({
                        client_id     : '############',
                        client_secret : '##################3',
                        grant_type    : 'refresh_token',
                        refresh_token : res.refresh_token
                    })
                });
            }, 10000);
        })
        .then((res) => res.json())
        .then(function(res) {
            fetch('https://discord.com/api/users/@me', {
                headers : {
                    authorization : `${res.token_type} ${res.access_token}`
                }
            })
                .then((res) => res.json())
                .then(function(res) {
                    const username = res.username;
                    info.textContent = username;
                });
        });
}

And Whenever I refresh my page the refresh token disappears.

But this code gives me the following error:

TypeError: Cannot read property 'json' of undefined

Just before I fetch the user/@me.

1 Answers

The problem is that in the then handler just before

.then((res) => res.json())

You are not returning the promise given to you by fetch, which is required when chaining promises. Here undefined is getting resolved because fetch is inside setInterval callback.

What you can do is - return a promise inside the then handler and resolve that promise to fetch call after your desired timeout / interval (since fetch returns a promise).

e.g. In your then handler, you can do this -

.then(function(res) {
return new Promise((resolve, reject) => {
  setInterval(() => {
    resolve(fetch('https://discord.com/api/oauth2/token/revoke', {
        method  : 'POST',
        headers : {
            'Content-Type' : 'application/x-www-form-urlencoded'
        },
        body : new URLSearchParams({
            client_id     : '############',
            client_secret : '##################3',
            grant_type    : 'refresh_token',
            refresh_token : res.refresh_token
        })
    }))
  }, 10000);
 })
})

However, do note that promises are resolved only once. So effectively, setInterval will only resolve the promise only once for you.

Related