@moteurio/plugin-auth-microsoft 0.0.0-stage → 2026.10.23-2
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/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +116 -0
- package/package.json +29 -3
- package/README.md +0 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PluginManifest, PluginRouteContext, PluginRouteContribution } from '@moteurio/types/Plugin.js';
|
|
2
|
+
import { type PluginInitContext as PluginContext } from '@moteurio/plugin-sdk';
|
|
3
|
+
export declare const manifest: PluginManifest;
|
|
4
|
+
export declare function init(_ctx: PluginContext): void;
|
|
5
|
+
export declare function getRoutes(ctx: PluginRouteContext): PluginRouteContribution;
|
|
6
|
+
export declare function getAuthProviders(): {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
loginPath: string;
|
|
11
|
+
callbackPath: string;
|
|
12
|
+
}[];
|
|
13
|
+
declare const _default: {
|
|
14
|
+
manifest: PluginManifest;
|
|
15
|
+
init: typeof init;
|
|
16
|
+
getRoutes: typeof getRoutes;
|
|
17
|
+
getAuthProviders: typeof getAuthProviders;
|
|
18
|
+
};
|
|
19
|
+
export default _default;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC7G,OAAO,EASH,KAAK,iBAAiB,IAAI,aAAa,EAC1C,MAAM,sBAAsB,CAAC;AAe9B,eAAO,MAAM,QAAQ,EAAE,cAOtB,CAAC;AAEF,wBAAgB,IAAI,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAG;AAiFlD,wBAAgB,SAAS,CAAC,GAAG,EAAE,kBAAkB,GAAG,uBAAuB,CAM1E;AAED,wBAAgB,gBAAgB;;;;;;IAU/B;;;;;;;AAED,wBAA+D"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microsoft Entra ID (Azure AD) OAuth login.
|
|
3
|
+
* Env: AUTH_MICROSOFT_CLIENT_ID, AUTH_MICROSOFT_CLIENT_SECRET, AUTH_MICROSOFT_REDIRECT_URI,
|
|
4
|
+
* optional AUTH_MICROSOFT_TENANT (default `common`: work + personal Microsoft accounts).
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { beginOAuth, completeOAuth, exchangeAuthorizationCode, emailFromOidcClaims, fetchOidcUserInfo, oauthConfig, redirectAfterLogin, redirectLoginFailed } from '@moteurio/plugin-sdk';
|
|
8
|
+
import { loginWithProvider } from '@moteurio/core/auth.js';
|
|
9
|
+
const PROVIDER = 'microsoft';
|
|
10
|
+
const NOT_OFFERED = { error: 'Microsoft sign-in is not available on this server.' };
|
|
11
|
+
function tenant() {
|
|
12
|
+
return process.env.AUTH_MICROSOFT_TENANT?.trim() || 'common';
|
|
13
|
+
}
|
|
14
|
+
function microsoftBase() {
|
|
15
|
+
return `https://login.microsoftonline.com/${tenant()}/oauth2/v2.0`;
|
|
16
|
+
}
|
|
17
|
+
export const manifest = {
|
|
18
|
+
id: 'auth-microsoft',
|
|
19
|
+
label: 'Microsoft',
|
|
20
|
+
description: 'Sign in with Microsoft work or school accounts',
|
|
21
|
+
source: 'opensource',
|
|
22
|
+
kind: 'optional',
|
|
23
|
+
scope: 'global'
|
|
24
|
+
};
|
|
25
|
+
export function init(_ctx) { }
|
|
26
|
+
function createMicrosoftRouter(ctx) {
|
|
27
|
+
const router = Router();
|
|
28
|
+
router.get('/microsoft', (req, res) => {
|
|
29
|
+
const config = oauthConfig(PROVIDER);
|
|
30
|
+
if (!config) {
|
|
31
|
+
res.status(404).json(NOT_OFFERED);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const params = new URLSearchParams({
|
|
35
|
+
client_id: config.clientId,
|
|
36
|
+
redirect_uri: config.redirectUri,
|
|
37
|
+
response_type: 'code',
|
|
38
|
+
scope: 'openid profile email User.Read',
|
|
39
|
+
response_mode: 'query',
|
|
40
|
+
state: beginOAuth(req, res, PROVIDER)
|
|
41
|
+
});
|
|
42
|
+
res.redirect(`${microsoftBase()}/authorize?${params.toString()}`);
|
|
43
|
+
});
|
|
44
|
+
router.get('/microsoft/callback', async (req, res) => {
|
|
45
|
+
const config = oauthConfig(PROVIDER);
|
|
46
|
+
if (!config) {
|
|
47
|
+
res.status(404).json(NOT_OFFERED);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const started = completeOAuth(req, res, PROVIDER);
|
|
51
|
+
if (!started)
|
|
52
|
+
return redirectLoginFailed(res, 'state');
|
|
53
|
+
const code = req.query.code;
|
|
54
|
+
if (typeof code !== 'string' || !code)
|
|
55
|
+
return redirectLoginFailed(res, 'failed');
|
|
56
|
+
try {
|
|
57
|
+
const tokens = await exchangeAuthorizationCode(`${microsoftBase()}/token`, config, code);
|
|
58
|
+
const claims = await fetchOidcUserInfo('https://graph.microsoft.com/oidc/userinfo', tokens.access_token);
|
|
59
|
+
const email = emailFromOidcClaims(claims);
|
|
60
|
+
if (!email)
|
|
61
|
+
return redirectLoginFailed(res, 'email');
|
|
62
|
+
const sub = typeof claims.sub === 'string' ? claims.sub : '';
|
|
63
|
+
const name = typeof claims.name === 'string' ? claims.name : undefined;
|
|
64
|
+
const { token } = await loginWithProvider({ auth: { microsoftSub: sub }, email, name }, ctx.authCallbacks?.runOnboardingForNewUser);
|
|
65
|
+
redirectAfterLogin(res, token, started.next);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
if (err instanceof Error && err.message === 'User is not active') {
|
|
69
|
+
return redirectLoginFailed(res, 'inactive');
|
|
70
|
+
}
|
|
71
|
+
console.error('Microsoft auth error:', err);
|
|
72
|
+
redirectLoginFailed(res, 'failed');
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return router;
|
|
76
|
+
}
|
|
77
|
+
const openapi = {
|
|
78
|
+
'/auth/microsoft': {
|
|
79
|
+
get: {
|
|
80
|
+
summary: 'Redirect to Microsoft login',
|
|
81
|
+
tags: ['Auth'],
|
|
82
|
+
parameters: [{ name: 'next', in: 'query', required: false, schema: { type: 'string' } }],
|
|
83
|
+
responses: { '302': { description: 'Redirect to Microsoft' } }
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
'/auth/microsoft/callback': {
|
|
87
|
+
get: {
|
|
88
|
+
summary: 'Microsoft OAuth callback',
|
|
89
|
+
tags: ['Auth'],
|
|
90
|
+
parameters: [
|
|
91
|
+
{ name: 'code', in: 'query', required: true, schema: { type: 'string' } },
|
|
92
|
+
{ name: 'state', in: 'query', required: true, schema: { type: 'string' } }
|
|
93
|
+
],
|
|
94
|
+
responses: { '302': { description: 'Redirect to the app with token or error' } }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
export function getRoutes(ctx) {
|
|
99
|
+
return {
|
|
100
|
+
path: '/auth',
|
|
101
|
+
router: createMicrosoftRouter(ctx),
|
|
102
|
+
openapi: { paths: openapi }
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export function getAuthProviders() {
|
|
106
|
+
return [
|
|
107
|
+
{
|
|
108
|
+
id: 'microsoft',
|
|
109
|
+
label: 'Microsoft',
|
|
110
|
+
enabled: oauthConfig(PROVIDER) !== null,
|
|
111
|
+
loginPath: '/auth/microsoft',
|
|
112
|
+
callbackPath: '/auth/microsoft/callback'
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
export default { manifest, init, getRoutes, getAuthProviders };
|
package/package.json
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moteurio/plugin-auth-microsoft",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "2026.10.23-2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@moteurio/core": "^2026.10.23-2",
|
|
15
|
+
"@moteurio/plugin-sdk": "^2026.10.23-2",
|
|
16
|
+
"@moteurio/types": "^2026.10.23-2",
|
|
17
|
+
"express": "^4.19.2",
|
|
18
|
+
"openapi-types": "^12.1.3"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/express": "^5.0.3"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -b",
|
|
29
|
+
"clean": "rimraf dist",
|
|
30
|
+
"test": "vitest run --passWithNoTests"
|
|
31
|
+
}
|
|
6
32
|
}
|
package/README.md
DELETED