@555platform/author.ts 中文文档教程
Author.ts
用于 OAuth 2.0 的同构 Typescript 工具包,
Install
来自 npm
npm install @555platform/Author.ts
Initialize - client
import { WebAuth } from '@555platform/Author.ts';
const webAuth = new WebAuth({
domain: config.domain,
clientID: config.clientID,
responseType: 'code',
redirectURI: config.redirectURI,
scope: 'everything',
authServer: config.authServer
});
的 555 平台 以上是客户端 SDK 的典型初始化示例。 authServer
字段是可选的,默认为 555 平台生产服务器。
可用的响应类型有 code
、token
、id_token
和 id_token token
。
Initialize - server
服务器端的示例初始化。 请注意,目前 SDK 辅助函数仅支持 express.js。
serverAuth = ServerAuth({
domain: config.domain,
clientID: config.clientID,
clientSecret: config.clientSecret,
redirectURI: config.redirectURI,
authServer: config.authServer
});
Using response type code
使用响应类型代码时,您需要从客户端启动登录,这将带您进入 555 平台登录屏幕。 登录成功后,555 平台将重定向到应在应用服务器上实现的 URI。 为了实现这个流程,我们需要客户端和服务器端的代码。 让我们先从客户端代码开始。
const webAuth = new WebAuth({
domain: config.domain,
clientID: config.clientID,
responseType: 'code',
redirectURI: config.redirectURI,
scope: 'everything',
authServer: config.authServer
});
webAuth.login({ state: 'xyz' });
上面的代码将初始化 SDK 的客户端并使用响应类型代码启动登录流程。
现在在服务器端,我们需要使用 express.js 创建基本设置。 在 index.js 文件中:
const express = require('express');
const bodyParser = require('body-parser');
const cookieSession = require('cookie-session');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: ['victor is a cool cat']
})
);
require('./routes/authRoutes')(app);
const PORT = process.env.PORT || 3033;
app.listen(PORT);
由于我们将使用 cookie 来存储 555 平台访问令牌,因此我们还包含了 cookie-session
模块。
接下来我们需要创建处理从登录页面重定向的路由。 在文件 routes/authRoutes.js
中添加以下代码:
const { ServerAuth } = require('@555platform/Author.ts');
const config = require('./config');
serverAuth = ServerAuth({
domain: config.domain,
clientID: config.clientID,
clientSecret: config.clientSecret,
redirectURI: config.redirectURI,
authServer: config.authServer
});
serverAuth.serializeUser(payload => {
return payload.access_token;
});
serverAuth.deserializeUser(payload => {
return payload;
});
module.exports = app => {
app.use(serverAuth.session);
app.get(
'/auth/555/callback',
serverAuth.authenticate({
successRedirect: config.loginSuccess,
failureRedirect: config.loginFailure,
state: 'xyz',
nonce: '123'
})
);
}
我们做的第一件事是使用客户端 ID/密码、重定向 URI、域和可选的身份验证服务器 URL 初始化服务器端 SDK。
两次调用 serializeUser
和 deserializeUser
用于从 req.user
和 req.session.user。
我们还提供将用户对象附加到请求的 session
中间件。
最后,我们处理从 555 平台接收到 code
的 /auth/555/callback URI。 辅助函数 authenticate
负责访问令牌的整个代码交换,它将重定向到上面指定的成功或失败 URL。
还可以控制 authenticate
完成访问令牌的代码交换后发生的情况。 如果您不想自动重定向,请使用以下示例代码来引入您自己的逻辑:
app.get(
'/auth/555/callback',
serverAuth.authenticate({
state: 'xyz',
nonce: '123'
}), (req, res) => {
console.log('AUTH CHECK: ', req.auth)
if (req.auth) {
res.send({message: 'authed'})
return
}
res.status(401).send({message: 'unauthorized'})
}
);
注意:为了在 req.auth
中接收授权数据,请不要将函数传递给 serializeUser
和 反序列化用户
。 如果您这样做,req.auth
将不包含任何数据,而是 req.user
将包含您选择的反序列化信息。
Using response type implicit
对于隐式流程,您启动调用以从客户端登录并直接接收带有访问令牌和/或 ID 令牌的重定向 URL,而无需交换代码。 如果您想直接在客户端中处理身份验证,这将很有用。
使用以下示例代码使用隐式流程调用 SDK 启动登录:
import { WebAuth } from '@555platform/Author.ts';
.
.
.
const webAuth = new WebAuth({
domain: config.domain,
clientID: config.clientID,
responseType: 'id_token token',
redirectURI: config.implicitRedirectURI,
scope: 'openid email',
authServer: config.authServer
});
webAuth.login({ state: 'xyz' });
在这种情况下,登录完成后 555 平台将重定向到 redirectURI 中指定的 URL,示例值如下:
/implicit#access_token=<access_token>&expires_in=216000&id_token=<id_token>&scope=openid+email&state=xyz&token_type=Bearer
Identity APIs
身份 API 允许搜索用户或单个用户并更新用户信息.
Query for users
您可以对符合特定条件的用户执行查询,例如,user_name
以 rob
开头。 可以通过提供 skip
和 limit
参数对搜索进行分页。 下面是一个例子:
const identity = new Identity();
identity
.findUsers(
'<server token>',
{ user_name: 'regex(.*rob.*) options(i)' }
)
.then((data: any) => console.log("Found users:", data))
.catch((error: Error) => console.log("Error finding users", error));
Find single user by userId:
const identity = new Identity();
identity
.findUser(
"<server token>",
"10c8f37c-057a-11ea-a90f-784f4371df5c"
)
.then((data: any) => console.log("Found user:", data))
.catch((error: Error) => console.log("Error finding user", error));
Update user information
下面是一个更新 user_name
的例子:
const identity = new Identity();
identity
.updateUser(
"<server token>",
"10c8f37c-057a-11ea-a90f-784f4371df5c",
{
user_name: "Rob Tester"
}
)
.then((data: any) => console.log("Updated user:", data))
.catch((error: Error) => console.log("Error updating user", error));
Subdomains
子域是域的子域。 它们可用于将多个域分组为单个应用程序所拥有的域,但每个域代表不同的身份集。 例如,这对于在 Slack 中实现诸如工作空间之类的概念很有用。
Create Subdomain
const serverAuth = new ServerAuth({
domain: 'test.domain.com',
clientID: 'blahblahblah',
clientSecret: 'blahblahblah123',
redirectURI: '/auth/iris/callback',
authServer: 'http://localhost',
userinfoRoot: '/oauth2'
});
serverAuth
.createSubdomain('<application name>', '<application friendly name>')
.then(data => {
console.log(data)
})
.catch(error => {
console.log(error);
});
Find Subdomains
findSubdomains
函数将返回匹配 friendlyName(第一个参数)或域名(第二个参数)的域列表。 每个参数都被视为 *value*
的正则表达式,因此它可以匹配多个条目。
例如,
const serverAuth = new ServerAuth({
domain: 'test.domain.com',
clientID: 'blahblahblah',
clientSecret: 'blahblahblah123',
redirectURI: '/auth/iris/callback',
authServer: 'http://localhost',
userinfoRoot: '/oauth2'
});
serverAuth
.findSubdomains('bl', '')
.then(data => {
console.log('Found subdomaines', data)
})
.catch(error => {
console.log(error);
});
Login with Subdomain
要使用子域登录,请调用 buildSubdomainLoginURL
以检索要重定向到的 URL。 此 URL 将调用指定子域的作者登录。
serverAuth
.buildSubdomainLoginURL('<subdomain friendly name>', '<state>', '<nonce>', '<scopes or everything>')
.then(loginURL => {
console.log(loginURL)
})
.catch(error => {
console.log(error);
});
Getting public key for the token's domain
Author SDK 提供便捷的 API 来自动查找指定令牌的公钥。 这在验证可以从多个域接收 JWT 的服务器上的 JWT 签名时非常有用。
例子,
import { getPublicKeysForToken } from '@555platform/author.ts';
const jwtPublicKey = await getPublicKeysForToken(
accessToken,
config.authServerUrl,
15, // cache age in seconds, default 30s
);
Author.ts
Isomorphic Typescript toolkit for OAuth 2.0 with 555 Platform
Install
From npm
npm install @555platform/Author.ts
Initialize - client
import { WebAuth } from '@555platform/Author.ts';
const webAuth = new WebAuth({
domain: config.domain,
clientID: config.clientID,
responseType: 'code',
redirectURI: config.redirectURI,
scope: 'everything',
authServer: config.authServer
});
The above is example of typical initialization of client side SDK. authServer
field is optional and it will default to 555 Platform production server.
Available response types are code
, token
, id_token
, and id_token token
.
Initialize - server
Sample initialization on server side. Note, currently SDK helper functions support only express.js.
serverAuth = ServerAuth({
domain: config.domain,
clientID: config.clientID,
clientSecret: config.clientSecret,
redirectURI: config.redirectURI,
authServer: config.authServer
});
Using response type code
When using response type code you will need to initiate login from the client side that will take you to 555 Platform login screen. After successful login 555 Platform will redirect to URI that should be implemented on application server. In order to implement this flow we will need code on both client and server. Let's start with the client code first.
const webAuth = new WebAuth({
domain: config.domain,
clientID: config.clientID,
responseType: 'code',
redirectURI: config.redirectURI,
scope: 'everything',
authServer: config.authServer
});
webAuth.login({ state: 'xyz' });
Above code will initialize client side of SDK and initiate login flow with response type code.
Now on the server side we will need to create basic set up with express.js. In the index.js file:
const express = require('express');
const bodyParser = require('body-parser');
const cookieSession = require('cookie-session');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: ['victor is a cool cat']
})
);
require('./routes/authRoutes')(app);
const PORT = process.env.PORT || 3033;
app.listen(PORT);
Since we will be using cookie to store 555 Platform access token we also included cookie-session
module.
Next we need to create route that will handle redirect from login page. In file routes/authRoutes.js
add the following code:
const { ServerAuth } = require('@555platform/Author.ts');
const config = require('./config');
serverAuth = ServerAuth({
domain: config.domain,
clientID: config.clientID,
clientSecret: config.clientSecret,
redirectURI: config.redirectURI,
authServer: config.authServer
});
serverAuth.serializeUser(payload => {
return payload.access_token;
});
serverAuth.deserializeUser(payload => {
return payload;
});
module.exports = app => {
app.use(serverAuth.session);
app.get(
'/auth/555/callback',
serverAuth.authenticate({
successRedirect: config.loginSuccess,
failureRedirect: config.loginFailure,
state: 'xyz',
nonce: '123'
})
);
}
The first thing we did is to initialize server side SDK with client ID/secret, redirect URI, domain and optional auth server URL.
Two calls serializeUser
and deserializeUser
are used to put/retrieve access token from the req.user
and req.session.user
.
We are also providing session
middleware that attaches user object to the request.
Finally, we handle /auth/555/callback URI that received code
from 555 Platform. Helper function authenticate
takes care of entire exchange of code for access token and it will redirect to either success or failure URLs as specified above.
It is also possible to control what happens after authenticate
completes code exchange for access token. If you rather not automatically redirect use the following sample code instead to introduce your own logic:
app.get(
'/auth/555/callback',
serverAuth.authenticate({
state: 'xyz',
nonce: '123'
}), (req, res) => {
console.log('AUTH CHECK: ', req.auth)
if (req.auth) {
res.send({message: 'authed'})
return
}
res.status(401).send({message: 'unauthorized'})
}
);
Note: In order to receive authorization data in req.auth
do not pass functions to serializeUser
and deserializeUser
. If you do req.auth
will not contain any data but rather req.user
will contain deserialized information you selected.
Using response type implicit
For implicit flow you initiate call to login from the client and receive redirected URL with access token and/or id token directly without the need to exchange the code. This is useful if you want to handle authentication directly in the client.
To initiate login with implicit flow call SDK with the following sample code:
import { WebAuth } from '@555platform/Author.ts';
.
.
.
const webAuth = new WebAuth({
domain: config.domain,
clientID: config.clientID,
responseType: 'id_token token',
redirectURI: config.implicitRedirectURI,
scope: 'openid email',
authServer: config.authServer
});
webAuth.login({ state: 'xyz' });
In this case, after login is completed 555 Platform will redirect to URL specified in redirectURI with the following sample values:
/implicit#access_token=<access_token>&expires_in=216000&id_token=<id_token>&scope=openid+email&state=xyz&token_type=Bearer
Identity APIs
Identity APIs allow seearching for users or single user and updating user information.
Query for users
You can perform a query for users that match certain criteria, for example, user_name
starts with rob
. Search can be paginated by providing skip
and limit
parameters. Here is an example:
const identity = new Identity();
identity
.findUsers(
'<server token>',
{ user_name: 'regex(.*rob.*) options(i)' }
)
.then((data: any) => console.log("Found users:", data))
.catch((error: Error) => console.log("Error finding users", error));
Find single user by userId:
const identity = new Identity();
identity
.findUser(
"<server token>",
"10c8f37c-057a-11ea-a90f-784f4371df5c"
)
.then((data: any) => console.log("Found user:", data))
.catch((error: Error) => console.log("Error finding user", error));
Update user information
Here is an example to update user_name
:
const identity = new Identity();
identity
.updateUser(
"<server token>",
"10c8f37c-057a-11ea-a90f-784f4371df5c",
{
user_name: "Rob Tester"
}
)
.then((data: any) => console.log("Updated user:", data))
.catch((error: Error) => console.log("Error updating user", error));
Subdomains
Subdomains are child domains of the domain. They are useful for grouping multiple domains as owned by single application but each domain represents different set of identities. This is useful for implementing concepts like workspaces in Slack for example.
Create Subdomain
const serverAuth = new ServerAuth({
domain: 'test.domain.com',
clientID: 'blahblahblah',
clientSecret: 'blahblahblah123',
redirectURI: '/auth/iris/callback',
authServer: 'http://localhost',
userinfoRoot: '/oauth2'
});
serverAuth
.createSubdomain('<application name>', '<application friendly name>')
.then(data => {
console.log(data)
})
.catch(error => {
console.log(error);
});
Find Subdomains
findSubdomains
function will return list of domains that match either friendlyName (first parameter) or domain name (second parameter). Each parameter is treated as regex of *value*
so it can match multiple entries.
For example,
const serverAuth = new ServerAuth({
domain: 'test.domain.com',
clientID: 'blahblahblah',
clientSecret: 'blahblahblah123',
redirectURI: '/auth/iris/callback',
authServer: 'http://localhost',
userinfoRoot: '/oauth2'
});
serverAuth
.findSubdomains('bl', '')
.then(data => {
console.log('Found subdomaines', data)
})
.catch(error => {
console.log(error);
});
Login with Subdomain
To login with subdomain call buildSubdomainLoginURL
to retrieve URL to redirect to. This URL will call Author login for specified subdomain.
serverAuth
.buildSubdomainLoginURL('<subdomain friendly name>', '<state>', '<nonce>', '<scopes or everything>')
.then(loginURL => {
console.log(loginURL)
})
.catch(error => {
console.log(error);
});
Getting public key for the token's domain
Author SDK provides convenience API to automatically look up public key for the specified token. This is useful when validating signature of the JWT on the server that can receive JWTs from multiple domains.
Example,
import { getPublicKeysForToken } from '@555platform/author.ts';
const jwtPublicKey = await getPublicKeysForToken(
accessToken,
config.authServerUrl,
15, // cache age in seconds, default 30s
);