@terrafirmagreg-team/auth 0.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -11
- package/src/lib/adapters.ts +4 -0
- package/src/lib/config.ts +6 -14
- package/src/lib/index.ts +1 -1
- package/src/lib/oauth.ts +17 -24
package/package.json
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@terrafirmagreg-team/auth",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"description": "GitHub OAuth sign-in and cookie sessions",
|
|
6
|
+
"license": "LGPL-3.0-only",
|
|
5
7
|
"exports": {
|
|
6
8
|
".": "./src/lib/index.ts",
|
|
7
|
-
"
|
|
8
|
-
"./src/*.ts",
|
|
9
|
-
"./src
|
|
10
|
-
"./src/*/index.ts",
|
|
11
|
-
"./src/*/index.tsx"
|
|
9
|
+
"./lib/*": [
|
|
10
|
+
"./src/lib/*.ts",
|
|
11
|
+
"./src/lib/*/index.ts"
|
|
12
12
|
]
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
|
-
"src"
|
|
16
|
-
"styles",
|
|
17
|
-
"styles.css",
|
|
18
|
-
"locales"
|
|
15
|
+
"src"
|
|
19
16
|
],
|
|
20
17
|
"dependencies": {
|
|
21
|
-
"@terrafirmagreg-team/data": "
|
|
18
|
+
"@terrafirmagreg-team/data": "1.2.0",
|
|
19
|
+
"arctic": "^3.7.0"
|
|
22
20
|
},
|
|
23
21
|
"devDependencies": {
|
|
24
22
|
"@types/node": "^26.6.5"
|
package/src/lib/adapters.ts
CHANGED
|
@@ -47,6 +47,9 @@ export function githubCookieAuth({
|
|
|
47
47
|
)
|
|
48
48
|
.catch(() => null);
|
|
49
49
|
cache.set(token, session);
|
|
50
|
+
session.then((s) => {
|
|
51
|
+
if (!s && cache.get(token) === session) cache.delete(token);
|
|
52
|
+
});
|
|
50
53
|
}
|
|
51
54
|
return session;
|
|
52
55
|
},
|
|
@@ -67,3 +70,4 @@ export function devCookieAuth({
|
|
|
67
70
|
},
|
|
68
71
|
};
|
|
69
72
|
}
|
|
73
|
+
|
package/src/lib/config.ts
CHANGED
|
@@ -12,16 +12,7 @@ export function authMode(): AuthMode {
|
|
|
12
12
|
|
|
13
13
|
export function authEnabled() {
|
|
14
14
|
if (authMode() === 'dev') return true;
|
|
15
|
-
return Boolean(
|
|
16
|
-
env('COMMENTS_TOKEN_SECRET') && env('GITHUB_COMMENTS_CLIENT_ID'),
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function authOwnerLogins() {
|
|
21
|
-
return (env('GITHUB_COMMENTS_OWNER_LOGINS') ?? '')
|
|
22
|
-
.split(',')
|
|
23
|
-
.map((login) => login.trim())
|
|
24
|
-
.filter(Boolean);
|
|
15
|
+
return Boolean(env('DISCUSSIONS_SECRET') && env('APP_CLIENT_ID'));
|
|
25
16
|
}
|
|
26
17
|
|
|
27
18
|
export interface AuthConfig {
|
|
@@ -38,14 +29,15 @@ export interface AuthConfig {
|
|
|
38
29
|
|
|
39
30
|
export function authConfig(): AuthConfig {
|
|
40
31
|
return {
|
|
41
|
-
clientId: env('
|
|
42
|
-
clientSecret: env('
|
|
43
|
-
tokenSecret: env('
|
|
32
|
+
clientId: env('APP_CLIENT_ID')!,
|
|
33
|
+
clientSecret: env('APP_SECRET')!,
|
|
34
|
+
tokenSecret: env('DISCUSSIONS_SECRET') ?? 'dev-token-secret',
|
|
44
35
|
cookieName: authCookie,
|
|
45
36
|
devCookieName: devAuthCookie,
|
|
46
37
|
callbackPath: '/api/comments/oauth/callback',
|
|
47
38
|
loginPath: '/api/comments/oauth/login',
|
|
48
|
-
scope: '
|
|
39
|
+
scope: '',
|
|
49
40
|
mode: authMode(),
|
|
50
41
|
};
|
|
51
42
|
}
|
|
43
|
+
|
package/src/lib/index.ts
CHANGED
|
@@ -2,7 +2,6 @@ export {
|
|
|
2
2
|
authConfig,
|
|
3
3
|
authEnabled,
|
|
4
4
|
authMode,
|
|
5
|
-
authOwnerLogins,
|
|
6
5
|
authCookie,
|
|
7
6
|
devAuthCookie,
|
|
8
7
|
type AuthConfig,
|
|
@@ -23,3 +22,4 @@ import { authConfig } from './config';
|
|
|
23
22
|
const flow = createOAuthFlow(authConfig);
|
|
24
23
|
|
|
25
24
|
export const { login, callback, logout, devLogin } = flow;
|
|
25
|
+
|
package/src/lib/oauth.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { decrypt, encrypt } from '@terrafirmagreg-team/data';
|
|
2
|
+
import { GitHub } from 'arctic';
|
|
2
3
|
import type { AuthConfig } from './config';
|
|
3
4
|
|
|
4
|
-
const GITHUB_AUTHORIZE = 'https://github.com/login/oauth/authorize';
|
|
5
|
-
const GITHUB_ACCESS_TOKEN = 'https://github.com/login/oauth/access_token';
|
|
6
5
|
const STATE_TTL = 10 * 60 * 1000;
|
|
7
6
|
const COOKIE_MAX_AGE = 60 * 60 * 24 * 365;
|
|
8
7
|
const COOKIE_BASE = 'Path=/; Max-Age=%d; SameSite=Lax; HttpOnly; Secure';
|
|
@@ -78,18 +77,24 @@ button:hover{opacity:.85}
|
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
export function createOAuthFlow(getConfig: () => AuthConfig): OAuthFlow {
|
|
80
|
+
function github(config: AuthConfig, self: string): GitHub {
|
|
81
|
+
return new GitHub(
|
|
82
|
+
config.clientId,
|
|
83
|
+
config.clientSecret,
|
|
84
|
+
`${self}${config.callbackPath}`,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
81
88
|
function login(request: Request): Response {
|
|
82
89
|
const config = getConfig();
|
|
83
90
|
if (config.mode === 'dev') return devLoginForm(request, config);
|
|
84
91
|
const self = new URL(request.url).origin;
|
|
85
92
|
const returnUrl = sameOrigin(new URL(request.url).searchParams.get('return'), self);
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
});
|
|
92
|
-
return Response.redirect(`${GITHUB_AUTHORIZE}?${params}`, 302);
|
|
93
|
+
const url = github(config, self).createAuthorizationURL(
|
|
94
|
+
encodeState(returnUrl, config.tokenSecret),
|
|
95
|
+
config.scope.split(' ').filter(Boolean),
|
|
96
|
+
);
|
|
97
|
+
return Response.redirect(url, 302);
|
|
93
98
|
}
|
|
94
99
|
|
|
95
100
|
async function devLogin(request: Request): Promise<Response> {
|
|
@@ -134,27 +139,14 @@ export function createOAuthFlow(getConfig: () => AuthConfig): OAuthFlow {
|
|
|
134
139
|
if (url.searchParams.get('error') || !code)
|
|
135
140
|
return Response.redirect(returnUrl, 302);
|
|
136
141
|
try {
|
|
137
|
-
const
|
|
138
|
-
method: 'POST',
|
|
139
|
-
headers: {
|
|
140
|
-
accept: 'application/json',
|
|
141
|
-
'content-type': 'application/x-www-form-urlencoded',
|
|
142
|
-
},
|
|
143
|
-
body: new URLSearchParams({
|
|
144
|
-
client_id: config.clientId,
|
|
145
|
-
client_secret: config.clientSecret,
|
|
146
|
-
code,
|
|
147
|
-
}),
|
|
148
|
-
});
|
|
149
|
-
const { access_token } = (await res.json()) as { access_token?: string };
|
|
150
|
-
if (!access_token) throw new Error('no token');
|
|
142
|
+
const tokens = await github(config, self).validateAuthorizationCode(code);
|
|
151
143
|
return new Response(null, {
|
|
152
144
|
status: 302,
|
|
153
145
|
headers: {
|
|
154
146
|
location: returnUrl,
|
|
155
147
|
'set-cookie': setCookieHeader(
|
|
156
148
|
config.cookieName,
|
|
157
|
-
encrypt(
|
|
149
|
+
encrypt(tokens.accessToken(), config.tokenSecret),
|
|
158
150
|
COOKIE_MAX_AGE,
|
|
159
151
|
),
|
|
160
152
|
},
|
|
@@ -180,3 +172,4 @@ export function createOAuthFlow(getConfig: () => AuthConfig): OAuthFlow {
|
|
|
180
172
|
|
|
181
173
|
return { login, devLogin, callback, logout };
|
|
182
174
|
}
|
|
175
|
+
|