OneDrive-Index-Cloudflare-Worker icon indicating copy to clipboard operation
OneDrive-Index-Cloudflare-Worker copied to clipboard

access token经常失效

Open Micraow opened this issue 4 years ago • 6 comments

当使用量大时

经常会出现access token过期失效的现象,原因尚不确定,清空缓存无效,必须要手动获取新的refresh token,非常麻烦,影响使用。如果项目还在维护,望修复!

Micraow avatar Apr 14 '20 03:04 Micraow

同遇到本问题。 {"code":"InvalidAuthenticationToken","message":"Access token has expired.","innerError":{"request-id":"dd6749ea-15c0-4ae9-99cd-b8046be4871b","date":"2020-04-18T04:38:07"}}

ryank231231 avatar Apr 18 '20 04:04 ryank231231

{"code":"InvalidAuthenticationToken","message":"Access token has expired.","innerError":{"request-id":"6ad4dc2a-967f-42d0-82e7-542f28c0a2e1","date":"2020-04-18T08:02:27"}} 和你一样,不知道定时刷新缓存有没有用,或定时刷新access token有没有用。本来准备用idm一直站点探测,触发onedrive API,达到E5保活,没想到一会就500错误,打开网站就这样了。

Micraow avatar Apr 18 '20 08:04 Micraow

有时放着放着就这样了,还不知道怎么解决

Micraow avatar Apr 18 '20 08:04 Micraow

我怀疑这个是由于,Cloudflare 的多个节点同时 refresh 了 token,但同一时刻只能有一个 access_token 是合法的。 解决方案有三:

  • 每次都 refresh access_token 不做 cache (有可能会被 rate limit,但没查到相关的文档说明)
  • 使用 Cloudflare Worker KV 全局存储 access_token (这个充值才能使用)
  • 使用其他方式共享全局 access_token ,比如使用 firebase

const AUTH_TOKEN = "<firebase_token>";

const timestamp = ()=>Math.floor(Date.now() / 1000 );

/**
 * Get access token for microsoft graph API endpoints. Refresh token if needed.
 */
async function getAccessToken() {
    // if (_accessToken) return _accessToken;
    let data = await (await fetch(`https://stroage-c8e2a.firebaseio.com/cred.json?auth=${AUTH_TOKEN}`)).json();
    if(data && data.access_token && timestamp() < data.expire_at){
        return  data.access_token;
    }
    resp = await fetch("https://login.microsoftonline.com/common/oauth2/v2.0/token", {
        method: "POST",
        body: `client_id=${config.client_id}&redirect_uri=${config.redirect_uri}&client_secret=${config.client_secret}
    &refresh_token=${config.refresh_token}&grant_type=refresh_token`,
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        }
    });
    if (resp.ok) {
        console.info("access_token refresh success.")
        let data = await resp.json()
        data.expire_at = timestamp() + data.expires_in
        _accessToken = data.access_token
        return _accessToken;
    } else throw `getAccessToken error ${ JSON.stringify(await resp.text())}`
}

但现在并无法确实是该原因造成的 InvalidAuthenticationToken ,所以没有进行修复。欢迎提供更多的线索。

heymind avatar Apr 21 '20 01:04 heymind

我将刷新缓存与令牌的部分提前,增加了定时任务,还是没有用,不知道怎么做了。

Micraow avatar Apr 21 '20 01:04 Micraow

there are different ways you could fix this but what i'm doing is hosting my token on another place

ex my cronjob runs every 40minutes since token expires every 60min.

php -q /hostdata/example.com/generate_token.php > /hostdata/example.com/public_html/token.txt

generate_token.php

<?php
    $curl = curl_init();
    curl_setopt_array($curl, array(
        CURLOPT_URL => "https://login.microsoftonline.com/common/oauth2/v2.0/token",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => "",
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => "POST",
        CURLOPT_HTTPHEADER => array(
            "Content-type"   => "application/x-www-form-urlencoded",
            "Content-Length" => 144
        ),
        CURLOPT_POSTFIELDS  => array(
            "client_id"     => 'xxxxxxxxxxxxxxxxxxxxxxxxxxx',
            "redirect_uri"  => 'https://heymind.github.io/tools/microsoft-graph-api-auth',
            "client_secret" => 'xxxxxxxxxxxxxxx',
            "refresh_token" => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
            "grant_type"    => 'refresh_token'),
    ));

    $response = curl_exec($curl);
    curl_close($curl);
    $_token = json_decode($response, true);
    print_r($_token["access_token"]);
?>

worker

async function getAccessToken() {
    let url = 'https://example.com/token.txt';
    let response = await fetch(url);
    if (response.ok) { 
       let json = await response.text();
       return json;
    } else {
       console.log(response.status);
    }
};

this of course is out of the "box" but this also reduces the loading time by 1.0ms 🌝

PS if anyone finds your "token.txt" they could use it but you can also setup web user with apache or nginx and replace https://example.com/token.txt with user:password https://user:[email protected]/token.txt that should do it.

theraw avatar Aug 05 '20 17:08 theraw