Skip to content

Commit 43a6d24

Browse files
authoredSep 16, 2021
feat: support new token formats and user-to-server token type (#200)
1 parent d7fc507 commit 43a6d24

File tree

4 files changed

+84
-26
lines changed

4 files changed

+84
-26
lines changed
 

‎README.md

+29-10
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ const { createTokenAuth } = require("@octokit/auth-token");
5858
</table>
5959

6060
```js
61-
const auth = createTokenAuth("1234567890abcdef1234567890abcdef12345678");
61+
const auth = createTokenAuth("ghp_PersonalAccessToken01245678900000000");
6262
const authentication = await auth();
6363
// {
6464
// type: 'token',
65-
// token: '1234567890abcdef1234567890abcdef12345678',
65+
// token: 'ghp_PersonalAccessToken01245678900000000',
6666
// tokenType: 'oauth'
6767
// }
6868
```
@@ -73,17 +73,36 @@ The `createTokenAuth` method accepts a single argument of type string, which is
7373

7474
- [Personal access token](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line)
7575
- [OAuth access token](https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/)
76-
- Installation access token ([GitHub App Installation](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#authenticating-as-an-installation))
7776
- [GITHUB_TOKEN provided to GitHub Actions](https://developer.github.com/actions/creating-github-actions/accessing-the-runtime-environment/#environment-variables)
77+
- Installation access token ([server-to-server](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#authenticating-as-an-installation))
78+
- User authentication for installation ([user-to-server](https://docs.github.com/en/developers/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps))
7879

7980
Examples
8081

8182
```js
8283
// Personal access token or OAuth access token
83-
createTokenAuth("1234567890abcdef1234567890abcdef12345678");
84+
createTokenAuth("ghp_PersonalAccessToken01245678900000000");
85+
// {
86+
// type: 'token',
87+
// token: 'ghp_PersonalAccessToken01245678900000000',
88+
// tokenType: 'oauth'
89+
// }
90+
91+
// Installation access token or GitHub Action token
92+
createTokenAuth("ghs_InstallallationOrActionToken00000000");
93+
// {
94+
// type: 'token',
95+
// token: 'ghs_InstallallationOrActionToken00000000',
96+
// tokenType: 'installation'
97+
// }
8498

8599
// Installation access token or GitHub Action token
86-
createTokenAuth("v1.1234567890abcdef1234567890abcdef12345678");
100+
createTokenAuth("ghu_InstallationUserToServer000000000000");
101+
// {
102+
// type: 'token',
103+
// token: 'ghu_InstallationUserToServer000000000000',
104+
// tokenType: 'user-to-server'
105+
// }
87106
```
88107

89108
## `auth()`
@@ -137,7 +156,7 @@ The `auth()` method has no options. It returns a promise which resolves with the
137156
<code>string</code>
138157
</th>
139158
<td>
140-
Can be either <code>"oauth"</code> for personal access tokens and OAuth tokens, or <code>"installation"</code> for installation access tokens (includes <code>GITHUB_TOKEN</code> provided to GitHub Actions)
159+
Can be either <code>"oauth"</code> for personal access tokens and OAuth tokens, <code>"installation"</code> for installation access tokens (includes <code>GITHUB_TOKEN</code> provided to GitHub Actions), <code>"app"</code> for a GitHub App JSON Web Token, or <code>"user-to-server"</code> for a user authentication token through an app installation.
141160
</td>
142161
</tr>
143162
</tbody>
@@ -181,7 +200,7 @@ Here is a list of things you can do to retrieve further information
181200
Note that this does not work for installations. There is no way to retrieve permissions based on an installation access tokens.
182201

183202
```js
184-
const TOKEN = "1234567890abcdef1234567890abcdef12345678";
203+
const TOKEN = "ghp_PersonalAccessToken01245678900000000";
185204

186205
const auth = createTokenAuth(TOKEN);
187206
const authentication = await auth();
@@ -203,7 +222,7 @@ if (scopes.length) {
203222
### Find out if token is a personal access token or if it belongs to an OAuth app
204223

205224
```js
206-
const TOKEN = "1234567890abcdef1234567890abcdef12345678";
225+
const TOKEN = "ghp_PersonalAccessToken01245678900000000";
207226

208227
const auth = createTokenAuth(TOKEN);
209228
const authentication = await auth();
@@ -227,7 +246,7 @@ if (clientId) {
227246
Note that the `permissions` key is not set when authenticated using an installation access token.
228247

229248
```js
230-
const TOKEN = "1234567890abcdef1234567890abcdef12345678";
249+
const TOKEN = "ghp_PersonalAccessToken01245678900000000";
231250

232251
const auth = createTokenAuth(TOKEN);
233252
const authentication = await auth();
@@ -253,7 +272,7 @@ Both OAuth and installation access tokens can be used for git operations. Howeve
253272
This example is using the [`execa`](https://github.com/sindresorhus/execa) package to run a `git push` command.
254273

255274
```js
256-
const TOKEN = "1234567890abcdef1234567890abcdef12345678";
275+
const TOKEN = "ghp_PersonalAccessToken01245678900000000";
257276

258277
const auth = createTokenAuth(TOKEN);
259278
const { token, tokenType } = await auth();

‎src/auth.ts

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
import { Token, Authentication } from "./types";
22

3+
const REGEX_IS_INSTALLATION_LEGACY = /^v1\./;
4+
const REGEX_IS_INSTALLATION = /^ghs_/;
5+
const REGEX_IS_USER_TO_SERVER = /^ghu_/;
6+
37
export async function auth(token: Token): Promise<Authentication> {
4-
const tokenType =
5-
token.split(/\./).length === 3
6-
? "app"
7-
: /^v\d+\./.test(token)
8-
? "installation"
9-
: "oauth";
8+
const isApp = token.split(/\./).length === 3;
9+
const isInstallation =
10+
REGEX_IS_INSTALLATION_LEGACY.test(token) ||
11+
REGEX_IS_INSTALLATION.test(token);
12+
const isUserToServer = REGEX_IS_USER_TO_SERVER.test(token);
13+
14+
const tokenType = isApp
15+
? "app"
16+
: isInstallation
17+
? "installation"
18+
: isUserToServer
19+
? "user-to-server"
20+
: "oauth";
1021

1122
return {
1223
type: "token",

‎src/types.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ export type AppAuthentication = {
2929
tokenType: "app";
3030
token: Token;
3131
};
32+
export type UserToServerAuthentication = {
33+
type: "token";
34+
tokenType: "user-to-server";
35+
token: Token;
36+
};
3237
export type Authentication =
3338
| OAuthTokenAuthentication
3439
| InstallationTokenAuthentication
35-
| AppAuthentication;
40+
| AppAuthentication
41+
| UserToServerAuthentication;

‎test/index.test.ts

+31-9
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ import fetchMock, { MockMatcherFunction } from "fetch-mock";
44
import { createTokenAuth } from "../src/index";
55

66
test("README example", async () => {
7-
const auth = createTokenAuth("1234567890abcdef1234567890abcdef12345678");
7+
const auth = createTokenAuth("ghp_PersonalAccessToken01245678900000000");
88
const authentication = await auth();
99

1010
expect(authentication).toEqual({
1111
type: "token",
12-
token: "1234567890abcdef1234567890abcdef12345678",
12+
token: "ghp_PersonalAccessToken01245678900000000",
1313
tokenType: "oauth",
1414
});
1515
});
1616

17-
test("installation token", async () => {
17+
test("installation token (old format)", async () => {
1818
const auth = createTokenAuth("v1.1234567890abcdef1234567890abcdef12345678");
1919
const authentication = await auth();
2020

@@ -25,6 +25,17 @@ test("installation token", async () => {
2525
});
2626
});
2727

28+
test("installation token (new format)", async () => {
29+
const auth = createTokenAuth("ghs_InstallallationOrActionToken00000000");
30+
const authentication = await auth();
31+
32+
expect(authentication).toEqual({
33+
type: "token",
34+
token: "ghs_InstallallationOrActionToken00000000",
35+
tokenType: "installation",
36+
});
37+
});
38+
2839
test("JSON Web Token (GitHub App Authentication)", async () => {
2940
const auth = createTokenAuth(
3041
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOi0zMCwiZXhwIjo1NzAsImlzcyI6MX0.q3foRa78U3WegM5PrWLEh5N0bH1SD62OqW66ZYzArp95JBNiCbo8KAlGtiRENCIfBZT9ibDUWy82cI4g3F09mdTq3bD1xLavIfmTksIQCz5EymTWR5v6gL14LSmQdWY9lSqkgUG0XCFljWUglEP39H4yeHbFgdjvAYg3ifDS12z9oQz2ACdSpvxPiTuCC804HkPVw8Qoy0OSXvCkFU70l7VXCVUxnuhHnk8-oCGcKUspmeP6UdDnXk-Aus-eGwDfJbU2WritxxaXw6B4a3flTPojkYLSkPBr6Pi0H2-mBsW_Nvs0aLPVLKobQd4gqTkosX3967DoAG8luUMhrnxe8Q"
@@ -39,6 +50,17 @@ test("JSON Web Token (GitHub App Authentication)", async () => {
3950
});
4051
});
4152

53+
test("User-to-server token (User authentication through app installation)", async () => {
54+
const auth = createTokenAuth("ghu_InstallationUserToServer000000000000");
55+
const authentication = await auth();
56+
57+
expect(authentication).toEqual({
58+
type: "token",
59+
token: "ghu_InstallationUserToServer000000000000",
60+
tokenType: "user-to-server",
61+
});
62+
});
63+
4264
test("invalid token", async () => {
4365
const auth = createTokenAuth("whatislove");
4466
const authentication = await auth();
@@ -88,26 +110,26 @@ test("OAuth token with prefix", async () => {
88110

89111
test("JWT with prefix", async () => {
90112
const auth = createTokenAuth(
91-
"token 1234567890abcdef1234567890abcdef12345678"
113+
"token ghp_PersonalAccessToken01245678900000000"
92114
);
93115
const authentication = await auth();
94116

95117
expect(authentication).toEqual({
96118
type: "token",
97-
token: "1234567890abcdef1234567890abcdef12345678",
119+
token: "ghp_PersonalAccessToken01245678900000000",
98120
tokenType: "oauth",
99121
});
100122
});
101123

102124
test("JWT with capitalized prefix", async () => {
103125
const auth = createTokenAuth(
104-
"Token 1234567890abcdef1234567890abcdef12345678"
126+
"Token ghp_PersonalAccessToken01245678900000000"
105127
);
106128
const authentication = await auth();
107129

108130
expect(authentication).toEqual({
109131
type: "token",
110-
token: "1234567890abcdef1234567890abcdef12345678",
132+
token: "ghp_PersonalAccessToken01245678900000000",
111133
tokenType: "oauth",
112134
});
113135
});
@@ -129,7 +151,7 @@ test("JWT with capitalized prefix", async () => {
129151
test('auth.hook(request, "GET /user")', async () => {
130152
const expectedRequestHeaders = {
131153
accept: "application/vnd.github.v3+json",
132-
authorization: "token 1234567890abcdef1234567890abcdef12345678",
154+
authorization: "token ghp_PersonalAccessToken01245678900000000",
133155
"user-agent": "test",
134156
};
135157

@@ -148,7 +170,7 @@ test('auth.hook(request, "GET /user")', async () => {
148170
},
149171
});
150172

151-
const { hook } = createTokenAuth("1234567890abcdef1234567890abcdef12345678");
173+
const { hook } = createTokenAuth("ghp_PersonalAccessToken01245678900000000");
152174
const { data } = await hook(requestMock, "GET /user");
153175

154176
expect(data).toStrictEqual({ id: 123 });

0 commit comments

Comments
 (0)
Please sign in to comment.