Onedrive API的使用
前言
OneDrive 是微软公司提供的一项云存储服务。用户可以通过 Microsoft 账户注册 OneDrive 后获得一定量的免费存储空间,例如起初通常有 5GB 的免费存储空间。OneDrive 支持多种操作系统,包括 Windows、macOS、iOS、Android 等。用户可以在不同设备上同步文件,并能够通过设置共享链接与他人共享文件。
对我来说Onedrive是一个很不错的云同步工具,我日常用它来进行笔记数据的多端同步,然后搭配Obsidian这类Local First的笔记APP进行使用,就可以安心地在多端进行笔记同步(顺便完成数据的备份)。总得来说,5GB的免费空间对于笔记这类文档资源来说可以用好多年了,且Onedrive的文件同步真的很快速且安全,很少出现同步错误的情况。
Onedrive同样提供了API的方式让开发者去访问授权用户的存储空间,进行存储空间内文件的增删改查相关操作,以便开发集成Onedrive的应用。不过我这里主要是利用Onedrive的API去接入自动化服务,以便可以让自动化服务能够修改特定文件达到个人信息流入口聚合的功能。
虽说这里我使用Onedrive API的目的只是为了访问自身的存储空间,但实际上访问其它授权用户的存储空间也是一样的流程,没有区别。
前置准备
目前使用Onedrive的API都需要先到Microsoft Azure去注册一个应用[1]:

注册应用要填的内容很少,除了应用名称,就是选择应用面向的微软账户类型了(一般选个人账户就行);还有一个重定向URI是可选的,这个就是用来返回用户授权码的回调地址,也就是当微软用户对当前应用完成授权后会返回的一个地址(其中授权码会以code=xxx的形式放在路径中)。

如果是像我这样纯个人使用,重定向URI填个localhost的地址就行,也能拿到授权码。
添加API权限
注册完应用后,需要添加该应用的具体要使用权限点,以便向用户进行授权申请。

Onedrive相关的API权限都放在Microsoft Graph分组中,直接在该分组中进行搜索查找即可。

对于Onedrive来说,常用的权限无非就是文件的读写了,因此找到Files一栏,根据需要自己找到合适范围的读写权限点即可:

不过不难发现,这里的读写权限覆盖范围实际上是由小及大的,其中对于Files.ReadWrite.AppFolder这个权限点来说,它能对Onedrive的应用文件夹下拥有读写权限,这也是很多Onedrive第三方应用所选的权限点。

除了读写权限,Onedrive应用还有一个权限也是经常要用到的,就是offline_access这个权限,该权限可以保证在授权完成后哪怕用户本身没有在线也可以使用进行授权的API对数据进行访问和操作。

创建客户端密码
在基于请求获取access token(访问令牌)和refresh token(刷新令牌)时,除了auth code/refresh token,还要加上客户端密码才能得到想要的token信息。当然,除了客户端密码这种形式,还可以用证书(秘钥)的形式进行token的获取[2],理论上使用证书这种形式应该会更安全一点。


可以根据需要选择客户端密码的有效期,添加完后就会生成一个客户端密码,复制进行传参即可[3]。
授权流程
当应用注册以及相关的应用配置都完成了后,就可以开始基于API进行Onedrive的相关操作了。不过由于所有的API操作都需要用到access token,所以需要先完成授权,而授权流程如下:

如图所示,先完成授权得到授权码,然后兑换授权码就可以得到最初的access token以及refresh token;由于access token只有一个小时的有效期,当access token失效后就可以兑换之前的refresh token得到新的access token和新的refresh token。因此完成授权后,理论上可以长期得到有效的access token,保证后续API的正常请求。
关于 tenant
上述获取授权码和令牌的接口中,有一个tenant的参数,实际上就跟应用申请的账户类型有关:
common:对应的账户类型为组织和个人账户organizations:对应的账户类型为组织账户consumers:对应的账户为个人账户

举个例子,如果应用选择的账户类型为个人账户时,对应的授权接口地址如下:
如果传错了tenant(也就是用错了请求地址),则会得到如下的接口报错:
1 | The request is not valid for the application's 'userAudience' configuration. In order to use /common/ endpoint, the application must not be configured with 'Consumer' as the user audience. The userAudience should be configured with 'All' to use /common/ endpoint. |
Onedrive API
Onedrive API的本质就是对DriveItems进行操作,因此只需要查看DriveItems列出的API列表即可,根据需要自行索引。如果只是访问用户的存储空间,那么对应的接口Base URL[4]如下:
然后根据API列表给出的相对路径进行拼接即可得到完整的请求地址:

文件访问的方式
如果要访问具体的文件或文件夹,有两种方式:
- 一种是通过
item-id进行访问,即/drive/items/{item-id} - 而另一种就很符合直觉,即通过文件的绝对路径进行访问,
/drive/root:/path/to/file
虽然很多接口都只列出了item-id形式的API地址,不过实测使用文件的绝对路径方式也能正常请求,因此我个人采用的事基于文件路径的形式进行接口请求。举个例子,如果在Onedrive存储空间下有个xxx文件夹,xxx文件夹中有个test.md的文件,那么下载该文件的请求地址为:
access token 的使用
对接过使用JWT的接口的人对这套流程应该很熟悉了,就是在请求头里加上一个Authorization头:
1 | Authorization: `bearer ${accessToken}` |
常见接口错误
IDX14100: JWT is not well formed
这个错误实际上是使用过期的access token进行接口请求时发出的错误信息[5],然而这个错误信息很不准确,乍一看还以为JWT的问题。

为了避免使用到过期的access token,我的做法是每次进行API请求前都使用refresh token得到一个新的access token,当然实际应用不推荐这么做,毕竟我这调用API的频率比较低🙈。
参考文档
- 微软身份平台和 OAuth 2.0 授权代码流 - Microsoft identity platform | Microsoft Learn 使用授权码、
access token以及refresh token的流程 - remotely-save/src/fsOnedrive.ts at master · remotely-save/remotely-save 需要的
onedrive权限可以参考这里,但是这里使用了App文件夹下的读写权限 - dkatavic/onedrive-api: OneDrive API module for Node.js
- DriveItem - OneDrive API - OneDrive dev center | Microsoft Learn
DriveItem是onedrive的操作对象,涉及到很多种动作 - 使用 Microsoft Graph 创建应用 - OneDrive API - OneDrive dev center | Microsoft Learn 使用
Onedrive API前需要创建一个应用(以便进行授权)
https://learn.microsoft.com/zh-cn/onedrive/developer/rest-api/getting-started/app-registration?view=odsp-graph-online#register-your-app-with-microsoft ↩︎
https://learn.microsoft.com/zh-cn/entra/identity-platform/v2-oauth2-auth-code-flow#request-an-access-token-with-a-certificate-credential ↩︎
https://learn.microsoft.com/zh-cn/entra/identity-platform/v2-oauth2-auth-code-flow#request-an-access-token-with-a-client_secret ↩︎
https://learn.microsoft.com/zh-cn/onedrive/developer/rest-api/?view=odsp-graph-online#microsoft-graph-root-resources ↩︎
InvalidAuthenticationToken with https://graph.microsoft.com/v1.0/me/calendar/events - Microsoft Q&A ↩︎