@stonyx/oauth 0.1.1-alpha.3 → 0.1.1-alpha.30
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/README.md +190 -2
- package/dist/auth-request.d.ts +132 -0
- package/dist/auth-request.js +235 -0
- package/dist/main.d.ts +121 -0
- package/dist/main.js +194 -0
- package/dist/oauth-flow.d.ts +30 -0
- package/dist/oauth-flow.js +83 -0
- package/dist/providers/discord.d.ts +30 -0
- package/dist/providers/discord.js +43 -0
- package/dist/session-manager.d.ts +20 -0
- package/dist/session-manager.js +30 -0
- package/dist/ticket-store.d.ts +103 -0
- package/dist/ticket-store.js +106 -0
- package/dist/token-manager.d.ts +15 -0
- package/dist/token-manager.js +24 -0
- package/package.json +40 -9
- package/src/auth-request.ts +330 -0
- package/src/main.ts +259 -0
- package/src/{oauth-flow.js → oauth-flow.ts} +31 -7
- package/src/providers/{discord.js → discord.ts} +29 -3
- package/src/{session-manager.js → session-manager.ts} +19 -6
- package/src/ticket-store.ts +123 -0
- package/src/token-manager.ts +35 -0
- package/src/types/node.d.ts +19 -0
- package/src/types/stonyx-events.d.ts +4 -0
- package/src/types/stonyx-rest-server.d.ts +11 -0
- package/src/types/stonyx.d.ts +38 -0
- package/src/auth-request.js +0 -74
- package/src/main.js +0 -83
- package/src/token-manager.js +0 -26
package/src/auth-request.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { Request } from '@stonyx/rest-server';
|
|
2
|
-
|
|
3
|
-
export default class AuthRequest extends Request {
|
|
4
|
-
constructor(oauth) {
|
|
5
|
-
super();
|
|
6
|
-
this.oauth = oauth;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
handlers = {
|
|
10
|
-
get: {
|
|
11
|
-
'/': ({ headers }) => {
|
|
12
|
-
const sessionId = headers['session-id'];
|
|
13
|
-
if (!sessionId) return 401;
|
|
14
|
-
|
|
15
|
-
const user = this.oauth.getSession(sessionId);
|
|
16
|
-
if (!user) return 401;
|
|
17
|
-
|
|
18
|
-
return user;
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
'/login/:provider': (req, state) => {
|
|
22
|
-
const { provider: providerName } = req.params;
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const url = this.oauth.getAuthorizationUrl(providerName);
|
|
26
|
-
state.redirect = url;
|
|
27
|
-
} catch {
|
|
28
|
-
return 404;
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
'/callback/:provider': async (req, state) => {
|
|
33
|
-
const { provider: providerName } = req.params;
|
|
34
|
-
const { code, state: stateToken, error } = req.query;
|
|
35
|
-
|
|
36
|
-
if (error) {
|
|
37
|
-
if (this.oauth.frontendCallbackUrl) {
|
|
38
|
-
state.redirect = `${this.oauth.frontendCallbackUrl}?error=${encodeURIComponent(error)}`;
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
return 400;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!code) return 400;
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const session = await this.oauth.handleCallback(providerName, code, stateToken);
|
|
48
|
-
|
|
49
|
-
if (this.oauth.frontendCallbackUrl) {
|
|
50
|
-
const params = new URLSearchParams({
|
|
51
|
-
sessionId: session.sessionId,
|
|
52
|
-
expiresAt: session.expiresAt,
|
|
53
|
-
});
|
|
54
|
-
state.redirect = `${this.oauth.frontendCallbackUrl}?${params}`;
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return session;
|
|
59
|
-
} catch {
|
|
60
|
-
if (this.oauth.frontendCallbackUrl) {
|
|
61
|
-
state.redirect = `${this.oauth.frontendCallbackUrl}?error=auth_failed`;
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
return 500;
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
'/logout': ({ headers }) => {
|
|
69
|
-
const sessionId = headers['session-id'];
|
|
70
|
-
if (sessionId) this.oauth.logout(sessionId);
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
}
|
package/src/main.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import config from 'stonyx/config';
|
|
2
|
-
import log from 'stonyx/log';
|
|
3
|
-
import { waitForModule } from 'stonyx';
|
|
4
|
-
import { setup, emit } from '@stonyx/events';
|
|
5
|
-
import RestServer from '@stonyx/rest-server';
|
|
6
|
-
import TokenManager from './token-manager.js';
|
|
7
|
-
import SessionManager from './session-manager.js';
|
|
8
|
-
import AuthRequest from './auth-request.js';
|
|
9
|
-
|
|
10
|
-
setup(['authenticate']);
|
|
11
|
-
|
|
12
|
-
export default class OAuth {
|
|
13
|
-
providers = new Map();
|
|
14
|
-
pendingStates = new Map();
|
|
15
|
-
|
|
16
|
-
constructor() {
|
|
17
|
-
if (OAuth.instance) return OAuth.instance;
|
|
18
|
-
OAuth.instance = this;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async init() {
|
|
22
|
-
const { providers, sessionDuration, frontendCallbackUrl } = config.oauth;
|
|
23
|
-
this.frontendCallbackUrl = frontendCallbackUrl;
|
|
24
|
-
|
|
25
|
-
for (const [name, providerConfig] of Object.entries(providers)) {
|
|
26
|
-
const modulePath = providerConfig.module
|
|
27
|
-
? `${config.rootPath}/${providerConfig.module}`
|
|
28
|
-
: `./providers/${name}.js`;
|
|
29
|
-
const { default: Provider } = await import(modulePath);
|
|
30
|
-
const flow = new Provider(providerConfig);
|
|
31
|
-
this.providers.set(name, { flow, tokenManager: new TokenManager(flow) });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
this.sessionManager = new SessionManager(sessionDuration);
|
|
35
|
-
|
|
36
|
-
await waitForModule('rest-server');
|
|
37
|
-
RestServer.instance.mountRoute(AuthRequest, { name: 'auth', options: this });
|
|
38
|
-
|
|
39
|
-
log.oauth?.('OAuth module initialized');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
getProvider(name) {
|
|
43
|
-
const provider = this.providers.get(name);
|
|
44
|
-
if (!provider) throw new Error(`OAuth provider "${name}" is not configured`);
|
|
45
|
-
return provider;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
getAuthorizationUrl(providerName) {
|
|
49
|
-
const { flow } = this.getProvider(providerName);
|
|
50
|
-
const stateToken = crypto.randomUUID();
|
|
51
|
-
this.pendingStates.set(stateToken, Date.now());
|
|
52
|
-
return flow.buildAuthorizationUrl(stateToken);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async handleCallback(providerName, code, stateToken) {
|
|
56
|
-
if (!stateToken || !this.pendingStates.has(stateToken)) {
|
|
57
|
-
throw new Error('Invalid or missing state token');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const stateCreatedAt = this.pendingStates.get(stateToken);
|
|
61
|
-
this.pendingStates.delete(stateToken);
|
|
62
|
-
|
|
63
|
-
const TEN_MINUTES = 10 * 60 * 1000;
|
|
64
|
-
if (Date.now() - stateCreatedAt > TEN_MINUTES) {
|
|
65
|
-
throw new Error('State token has expired');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const { flow, tokenManager } = this.getProvider(providerName);
|
|
69
|
-
const tokens = await tokenManager.getTokens(code);
|
|
70
|
-
const rawUser = await flow.fetchUserInfo(tokens.accessToken);
|
|
71
|
-
const user = flow.normalizeUser(rawUser);
|
|
72
|
-
await emit('authenticate', user);
|
|
73
|
-
return this.sessionManager.create(user, tokens);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
getSession(sessionId) {
|
|
77
|
-
return this.sessionManager.validate(sessionId);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
logout(sessionId) {
|
|
81
|
-
this.sessionManager.destroy(sessionId);
|
|
82
|
-
}
|
|
83
|
-
}
|
package/src/token-manager.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export default class TokenManager {
|
|
2
|
-
constructor(flow) {
|
|
3
|
-
this.flow = flow;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
async getTokens(code) {
|
|
7
|
-
const tokens = await this.flow.exchangeCode(code);
|
|
8
|
-
tokens.expiresAt = Date.now() + (tokens.expiresIn * 1000);
|
|
9
|
-
return tokens;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async refresh(refreshToken) {
|
|
13
|
-
const tokens = await this.flow.refreshAccessToken(refreshToken);
|
|
14
|
-
tokens.expiresAt = Date.now() + (tokens.expiresIn * 1000);
|
|
15
|
-
return tokens;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async revoke(accessToken) {
|
|
19
|
-
return this.flow.revokeToken(accessToken);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
isExpired(tokenData) {
|
|
23
|
-
if (!tokenData?.expiresAt) return true;
|
|
24
|
-
return Date.now() >= tokenData.expiresAt;
|
|
25
|
-
}
|
|
26
|
-
}
|