节点和浏览器的 OAuth2 客户端
此软件包包含一个 OAuth2 客户端. 它旨在成为一个全能的OAuth2 工具库,用于Node.js,浏览器并用 Typescript 编写.
此 OAuth2 客户端只是 4个KB g, 它已经 0 个 依赖性和
依赖现代API 类 fetch() 财务报告和审定财务报表 网络加密 内置的
从18号节点开始.
要点
- 16KB 精密化 (5KB gziped).
- 无依取相.
authorization_code可选赠款 捷克 支助.password财务报告和审定财务报表client_credentials赠款.- (单位:千美元)
fetch()自动添加 Bearer 令牌并刷新它们 . - OAuth2 通过服务器元数据文档发现端点(RFC8414 (法语)) (中文(简体) ).
- OAuth2 托肯内览( C)RFC7662 (法语)) (中文(简体) ).
- OAuth 2.0的资源指标RFC8707 (法语)) (中文(简体) ).
- OAuth2 托肯撤销RFC7009 (法语)) (中文(简体) ).
- OAuth 2.0 多重响应类型编码惯例
安装
npm i @badgateway/oauth2-client
使用量
要开始,设置客户类.
import { OAuth2Client } from '@badgateway/oauth2-client';
const client = new OAuth2Client({
// The base URI of your OAuth2 server
server: 'https://my-auth-server/',
// OAuth2 client id
clientId: '...',
// OAuth2 client secret. Only required for 'client_credentials', 'password'
// flows. Don't specify this in insecure contexts, such as a browser using
// the authorization_code flow.
clientSecret: '...',
// The following URIs are all optional. If they are not specified, we will
// attempt to discover them using the oauth2 discovery document.
// If your server doesn't have support this, you may need to specify these.
// you may use relative URIs for any of these.
// Token endpoint. Most flows need this.
// If not specified we'll use the information for the discovery document
// first, and otherwise default to /token
tokenEndpoint: '/token',
// Authorization endpoint.
//
// You only need this to generate URLs for authorization_code flows.
// If not specified we'll use the information for the discovery document
// first, and otherwise default to /authorize
authorizationEndpoint: '/authorize',
// OAuth2 Metadata discovery endpoint.
//
// This document is used to determine various server features.
// If not specified, we assume it's on /.well-known/oauth2-authorization-server
discoveryEndpoint: '/.well-known/oauth2-authorization-server',
});
键
许多函数使用或返回“ OAuth2Token” 类型 。 此类型有: 形状 :
export type OAuth2Token = {
accessToken: string;
refreshToken: string | null;
/**
* When the Access Token expires.
*
* This is expressed as a unix timestamp in milliseconds.
*/
expiresAt: number | null;
/**
* If the server returned an OpenID Connect ID token, it will be stored here.
*/
idToken?: string;
};
客户端 证书授权.
const token = await client.clientCredentials();
刷新符号
const newToken = await client.refreshToken(oldToken);
密码授权 :
const token = await client.password({
username: '..',
password: '..',
});
授权 代码
这个 authorization_code 流是基于浏览器的应用程序的流,
大致包括三个主要步骤:
- 重新引导用户到授权端点, 让他们登录 .
- 授权端点以“ 代码” 查询重定向到应用程序 参数.
- 这个
code用于交换访问和刷新符号.
这个图书馆为这些步骤提供支持,但是没有要求 由于该系统大多是无国籍的,因此可以使用该系统的功能.
import { OAuth2Client, generateCodeVerifier } from 'client';
const client = new OAuth2Client({
server: 'https://authserver.example/',
clientId: '...',
// Note, if urls cannot be auto-detected, also specify these:
tokenEndpoint: '/token',
authorizationEndpoint: '/authorize',
});
重新引导用户到授权服务器
/**
* This generates a security code that must be passed to the various steps.
* This is used for 'PKCE' which is an advanced security feature.
*
* It doesn't break servers that don't support it, but it makes servers that
* so support it more secure.
*
* It's optional to pass this, but recommended.
*/
const codeVerifier = await generateCodeVerifier();
// In a browser this might work as follows:
document.location = await client.authorizationCode.getAuthorizeUri({
// URL in the app that the user should get redirected to after authenticating
redirectUri: 'https://my-app.example/',
// Optional string that can be sent along to the auth server. This value will
// be sent along with the redirect back to the app verbatim.
state: 'some-string',
codeVerifier,
scope: ['scope1', 'scope2'],
});
处理重定向到应用程序并获取令牌
const oauth2Token = await client.authorizationCode.getTokenFromCodeRedirect(
document.location,
{
/**
* The redirect URI is not actually used for any redirects, but MUST be the
* same as what you passed earlier to "authorizationCode"
*/
redirectUri: 'https://my-app.example/',
/**
* This is optional, but if it's passed then it also MUST be the same as
* what you passed in the first step.
*
* If set, it will verify that the server sent the exact same state back.
*/
state: 'some-string',
codeVerifier,
}
);
获取折叠器
使用 OAuth2- 保护的 API 时,通常您需要获得访问
符号,然后用一个 Authorization: Bearer
头曰.
因为进入标志的寿命有限,偶尔需要 刷新了这一堆潜在的管道.
为了方便这些,这个图书馆有一个"相提并论". 这是有效的 和常规抓取函数一样,但自动添加页眉 并在需要时自动刷新符号.
用法 :
import { OAuth2Client, OAuth2Fetch } from '@badgateway/oauth2-client';
const client = new OAuth2Client({
server: 'https://my-auth-server',
clientId: 'my-client-id'
});
const fetchWrapper = new OAuth2Fetch({
client: client,
/**
* You are responsible for implementing this function.
* it's purpose is to supply the 'initial' oauth2 token.
*/
getNewToken: async () => {
// Example
return client.clientCredentials();
// Another example
return client.authorizationCode.getToken({
code: '..',
redirectUri: '..',
});
// You can return null to fail the process. You may want to do this
// when a user needs to be redirected back to the authorization_code
// endpoints.
return null;
},
/**
* Optional. This will be called for any fatal authentication errors.
*/
onError: (err) => {
// err is of type Error
}
});
安排好后,你可以打电话 fetch 在新对象上调用您的 API,以及
图书馆会确保永远有 Bearer 头曰.
const response = fetchWrapper.fetch('https://my-api', {
method: 'POST',
body: 'Hello world'
});
用于以后与 FettleWrapper 一起使用的存储符
要在会话间保持用户登录, 您可能想要避免全部 重修正经. 要做到这一点,你需要存储认证符 某处.
抓取包有2个功能可以帮助实现 :
const fetchWrapper = new OAuth2Fetch({
client: client,
getNewToken: async () => {
// See above!
},
/**
* This function is called whenever the active token changes. Using this is
* optional, but it may be used to (for example) put the token in off-line
* storage for later usage.
*/
storeToken: (token) => {
document.localStorage.setItem('token-store', JSON.stringify(token));
},
/**
* Also an optional feature. Implement this if you want the wrapper to try a
* stored token before attempting a full re-authentication.
*
* This function may be async. Return null if there was no token.
*/
getStoredToken: () => {
const token = document.localStorage.getItem('token-store');
if (token) return JSON.parse(token);
return null;
}
});
获取中间软件函数
使用这个图书馆作为更传统的"中道器"可能更好.
OAuth2 Fetch 对象也显示 mw 函数返回中间软件
用于获取.
const mw = oauth2.mw();
const response = mw(
myRequest,
req => fetch(req)
);
这个语法看起来有些疯狂,如果你不习惯于制造中间的软件,但是 这将有效允许您使用“ 装饰” 已有的请求库 来自此 oauth2 库的功能.
使用 叮当 库 :
import { Client } from 'ketting';
import { OAuth2Client, OAuth2Fetch } from '@badgateway/oauth2-client';
/**
* Create the oauth2 client
*/
const oauth2Client = new OAuth2Client({
server: 'https://my-auth.example',
clientId: 'foo',
});
/**
* Create the 'fetch helper'
*/
const oauth2Fetch = new OAuth2Fetch({
client: oauth2Client,
});
/**
* Add the middleware to Ketting
*/
const ketting = new Client('http://api-root');
ketting.use(oauth2Fetch.mw());
回顾
入会( 二RFC7662 (法语)) 让你找到更多关于一个符号的信息, 例如它是否有效,它属于哪个用户,哪个oaut2客户端 用于生成等.
要使用, 您的授权服务器必须支持 入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入. 使用 元数据发现文件.
import { OAuth2Client } from '@badgateway/oauth2-client';
const client = new Client({
server: 'https://auth-server.example/',
clientId: '...',
/**
* Some servers require OAuth2 clientId/clientSecret to be passed.
* If they require it, specify it. If not it's fine to omit.
*/
clientSecret: '...',
});
// Get a token
const token = client.clientCredentials();
// Introspect!
console.log(client.introspect(token));
OAuth2 证书 client_id 财务报告和审定财务报表 client_secret 编码
OAuth2 允许用户编码 client_id 财务报告和审定财务报表 client_secret 或在一个
Authorization: Basic 页眉或 POST 请求身体.
Real-world OAuth2服务器可能支持其中之一,或两者兼有. OAuth2号卫星 光谱 需求 服务器支持授权头,而不要 建议使用尸体.
默认情况下,此库将使用 Authorization 头曰. OAuth2 还
要求客户%- 编码 client_id 财务报告和审定财务报表 client_secret不过
在实践中,如果你这样做,很多流行服务器会中断。 默认情况下, 此库
将 没有 % 编码除 : 字符键.
您可以使用 authenticatioMethod 旗帜 :
const client = new OAuth2Client({
server: 'https://auth-server.example/',
clientId: '...',
clientSecret: '...',
authenticationMethod: 'client_secret_post', // encode in POST body
});
目前支持以下3个值:
client_secret_post- 在POST体内编码client_secret_basic- 在授权信头中使用严格的编码 标准规则.client_secret_basic_interop- 在授权信头中使用较少的编码 严格的规则。 这是默认的,更可能与流行 服务器(至少一些Google和Ebay APIs想要这个).
目前OAuth 2.1草案更改建议使用
client_secret_post 而不是默认。 当文档稳定并获得
,此库也将切换到使用 client_secret_post 默认
在一个主要的释放.
如果您的 OAuth2 服务器支持 POST, 我们建议您使用 client_secret_post
因为这更可能不搭便车.
如果您使用 OAuth2 发现文档配置了客户端, 那么
服务器表示它更喜欢 client_secret_basic 我们也会违约到
严格的形式.
支持旧节点版本
这个软件包与现代浏览器和节点18一起在盒子外工作.
对于节点16和下方,使用此软件包的 2.x 版本并添加 多填充剂。 此套件的 2. x 分支的 README. md 包含更多信息 关于旧节点版本的确切步骤.