├── .editorconfig ├── .github └── FUNDING.yml ├── .gitignore ├── 42-screen-shot.jpeg ├── LICENSE ├── README.md ├── dist ├── index.d.ts ├── index.js └── types │ ├── TokenErrorType.d.ts │ ├── TokenErrorType.js │ ├── TokenType.d.ts │ ├── TokenType.js │ ├── UserType.d.ts │ └── UserType.js ├── example.ts ├── package-lock.json ├── package.json ├── src ├── index.ts └── types │ ├── TokenErrorType.ts │ ├── TokenType.ts │ └── UserType.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = tab 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ["https://www.buymeacoffee.com/imranbaali", "https://www.paypal.me/imran120"] 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | 4 | dist-ssr 5 | *.local -------------------------------------------------------------------------------- /42-screen-shot.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirwako/API42Client/340c2d1362876db892eba7922a3c7a0d88b50d11/42-screen-shot.jpeg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2009-2014 TJ Holowaychuk 4 | Copyright (c) 2013-2014 Roman Shtylman 5 | Copyright (c) 2014-2015 Douglas Christopher Wilson 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | 'Software'), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # API42Client 2 | API42Client is a class that help you interacte with 42 school api and get users data 3 | 4 | [![NPM Version][npm-version-image]][npm-url] 5 | [![NPM Install Size][npm-install-size-image]][npm-install-size-url] 6 | [![NPM Downloads][npm-downloads-image]][npm-downloads-url] 7 | 8 | ## Installation 9 | 10 | This is a [Node.js](https://nodejs.org/en/) module available through the 11 | [npm registry](https://www.npmjs.com/). 12 | 13 | Before installing, [download and install Node.js](https://nodejs.org/en/download/). 14 | 15 | If this is a brand new project, make sure to create a `package.json` first with 16 | the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file). 17 | 18 | Installation is done using the 19 | [`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): 20 | 21 | ```console 22 | $ npm install api42client 23 | ``` 24 | 25 | ## example file `run.js` 26 | ```js 27 | import Authenticator from "api42client"; 28 | 29 | // you can see the attached screen shot to know where get this variables 30 | const UID = "98a139943caaa7645f98b077445f8e84de4cb23e7668fb010a01b9c0ed20b8a4"; // Position -1- 31 | const SECRET = "b34df710754fbe173bfd202cd0bfdf05fcdc4dda3f22b4d76459a2a1e1c35f"; // Position -2- 32 | const REDIRECT_URI = "http://localhost:3000"; // Position -3- 33 | 34 | // 42 authenticator instance 35 | var app = new Authenticator(UID, SECRET, REDIRECT_URI); 36 | 37 | // after send the user to 42 site to authorize the app [example of 42 site: https://api.intra.42.fr/oauth/authorize?client_id=98a139f98b077445f8e84de4cb23e7668fb010a01b9c0ed20b8a4&redirect_uri=http%3A%2F%2Flocalhost%3A3000&response_type=code] 38 | // 42 redirect the user to the REDIRECT_URI (in this example is: http://localhost:3000) with the code in query string 39 | // like that: http://localhost:3000/?code=7a0cb1a9c5b0fd31a0eb9c5f854fc2386b1edc2179f73c76904d65f5aae4e9bc 40 | // get the code from the query string (code=7a0cb1a9c5b0fd31a0eb9c5f854fc2386b1edc2179f73c76904d65f5aae4e9bc) 41 | // and give it to get_Access_token function like below 42 | var token = app.get_Access_token("85a7e9c0bdbb53d6583064846c087e5e499b6b523f0602c46d1d422078feaf77"); 43 | 44 | token.then((data) => { 45 | // get the acces token of the user 46 | console.log("======================== auth user Data ========================="); 47 | console.log(data); 48 | console.log("========================= 42 user data =========================="); 49 | // get the user info from 42 api 50 | app.get_user_data(data.access_token).then((data) => { 51 | console.log(data); 52 | console.log("============================================================="); 53 | }); 54 | }).catch((err) => { 55 | console.log(err); 56 | }); 57 | ``` 58 | 59 | #### Configuration 60 | 61 | 1. Make sure you have install api42client package `npm i api42client` 62 | 2. Change UID in `Position -1-` with your values in 42 app (like in picture) 63 | 3. Change SECRET in `Position -2-` with your values in 42 app (like in picture) 64 | 4. Change REDIRECT_URI in `Position -3-` with your values in 42 app (like in picture) 65 | 66 | 42 app screen shot 67 | 68 | #### User flow 69 | 1. send the user to 42 site to authorize the app 70 | [it is the link below REDIRECT URL in 42 api page] 71 | 2. 42 api will redirect the user to the REDIRECT_URI with the code in query string 72 | 3. get the code from the query string (`code=7a0c...5f5aa9bc`) 73 | 4. give it to get_Access_token function like sourcecode in `index.mjs` file 74 | 75 | ## Running 76 | 77 | ```bash 78 | node run.js 79 | ``` 80 | 81 | Finally Congratulations 🎉 you will get all user info from 42 api 82 | 83 | ## License 84 | 85 | [MIT](LICENSE) 86 | 87 | ## Support 88 | #### This package costs me time to make and maintain every time. 89 | [I am very 😀 about every coffee!] 90 | 91 | Buy Me A Coffee 92 | 93 | [npm-downloads-image]: https://badgen.net/npm/dm/api42client 94 | [npm-downloads-url]: https://npmcharts.com/compare/api42client?minimal=true 95 | [npm-install-size-image]: https://badgen.net/packagephobia/install/api42client 96 | [npm-install-size-url]: https://packagephobia.com/result?p=api42client 97 | [npm-url]: https://www.npmjs.com/package/api42client 98 | [npm-version-image]: https://badgen.net/npm/v/api42client 99 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import TokenType from "./types/TokenType"; 2 | import TokenErrorType from "./types/TokenErrorType"; 3 | import UserType from "./types/UserType"; 4 | declare class Authenticator { 5 | uid: string; 6 | secret: string; 7 | redirect_uri: string; 8 | constructor(uid: string, secret: string, redirect_uri: string); 9 | get_Access_token(code: string): Promise; 10 | is_valid_token(access_token: string): Promise; 11 | get_user_data(access_token: string): Promise; 12 | } 13 | export default Authenticator; 14 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __generator = (this && this.__generator) || function (thisArg, body) { 12 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 13 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 14 | function verb(n) { return function (v) { return step([n, v]); }; } 15 | function step(op) { 16 | if (f) throw new TypeError("Generator is already executing."); 17 | while (_) try { 18 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 19 | if (y = 0, t) op = [op[0] & 2, t.value]; 20 | switch (op[0]) { 21 | case 0: case 1: t = op; break; 22 | case 4: _.label++; return { value: op[1], done: false }; 23 | case 5: _.label++; y = op[1]; op = [0]; continue; 24 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 25 | default: 26 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 27 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 28 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 29 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 30 | if (t[2]) _.ops.pop(); 31 | _.trys.pop(); continue; 32 | } 33 | op = body.call(thisArg, _); 34 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 35 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 36 | } 37 | }; 38 | Object.defineProperty(exports, "__esModule", { value: true }); 39 | var node_fetch_1 = require("node-fetch"); 40 | var GET_ACCESS_TOKEN_URL = "https://api.intra.42.fr/oauth/token"; 41 | var TEST_ACCESS_TOKEN = "https://api.intra.42.fr/oauth/token/info"; 42 | var GET_USER_DATA_URL = "https://api.intra.42.fr/v2/me"; 43 | var RESET_BOLD = "\u001b[22m"; 44 | var BOLD = "\u001b[1m"; 45 | var FG_GREEN = "\x1b[32m"; 46 | var RESET_COLOR = "\x1b[0m"; 47 | var FG_RED = "\x1b[31m"; 48 | var FG_YELLOW = "\x1b[33m"; 49 | var BOLD_FG_GREEN = "".concat(BOLD).concat(FG_GREEN); 50 | var RESET_BOLD_FG_GREEN = "".concat(RESET_BOLD).concat(RESET_COLOR); 51 | var BOLD_FG_RED = "".concat(BOLD).concat(FG_RED); 52 | var RESET_BOLD_FG_RED = "".concat(RESET_BOLD).concat(RESET_COLOR); 53 | var BOLD_FG_YELLOW = "".concat(BOLD).concat(FG_YELLOW); 54 | var RESET_BOLD_FG_YELLOW = "".concat(RESET_BOLD).concat(RESET_COLOR); 55 | var description = "\n\t\tAuthenticator\n\t\t\n\t\tThe Authenticator make you connect to the 42 School API with the Authorization Code flow,\n\t\tthis step for geting the Access-token That access token is used by the client to make API calls.\n\t\t\n\t\tOptions:\n\t\t- \"uid\" \t\t:\tyour 42 application's UID\n\t\t- \"secret\" \t\t:\tyour 42 application's SECRET\n\t\t- \"redirect_uri\" : \tURL to which 42 will redirect the user after granting authorization\n\t"; 56 | var Authenticator = /** @class */ (function () { 57 | function Authenticator(uid, secret, redirect_uri) { 58 | this.uid = uid; 59 | this.secret = secret; 60 | this.redirect_uri = redirect_uri; 61 | } 62 | Authenticator.prototype.get_Access_token = function (code) { 63 | return __awaiter(this, void 0, void 0, function () { 64 | var payload, res; 65 | return __generator(this, function (_a) { 66 | switch (_a.label) { 67 | case 0: 68 | payload = { 69 | grant_type: "authorization_code", 70 | client_id: this.uid, 71 | client_secret: this.secret, 72 | code: code, 73 | redirect_uri: this.redirect_uri, 74 | }; 75 | return [4 /*yield*/, (0, node_fetch_1.default)(GET_ACCESS_TOKEN_URL, { 76 | method: "POST", 77 | body: JSON.stringify(payload), 78 | headers: { 79 | "Content-Type": "application/json", 80 | }, 81 | })]; 82 | case 1: 83 | res = _a.sent(); 84 | if (!res.ok) return [3 /*break*/, 3]; 85 | return [4 /*yield*/, res.json()]; 86 | case 2: return [2 /*return*/, _a.sent()]; 87 | case 3: throw new Error("".concat(BOLD_FG_RED, "Error while getting access token").concat(RESET_BOLD_FG_RED, "\n ").concat(BOLD_FG_YELLOW, "Please be sure that you use the right:").concat(RESET_BOLD_FG_YELLOW, "\n - uid, secret and redirect_uri\n - and the right code getted from the 42 API\n")); 88 | } 89 | }); 90 | }); 91 | }; 92 | Authenticator.prototype.is_valid_token = function (access_token) { 93 | return __awaiter(this, void 0, void 0, function () { 94 | var header, res; 95 | return __generator(this, function (_a) { 96 | switch (_a.label) { 97 | case 0: 98 | header = { 99 | Authorization: "Bearer ".concat(access_token), 100 | }; 101 | return [4 /*yield*/, (0, node_fetch_1.default)(TEST_ACCESS_TOKEN, { 102 | method: "GET", 103 | headers: header, 104 | })]; 105 | case 1: 106 | res = _a.sent(); 107 | return [2 /*return*/, res.status == 200 ? true : false]; 108 | } 109 | }); 110 | }); 111 | }; 112 | Authenticator.prototype.get_user_data = function (access_token) { 113 | return __awaiter(this, void 0, void 0, function () { 114 | var header, res; 115 | return __generator(this, function (_a) { 116 | switch (_a.label) { 117 | case 0: 118 | header = { 119 | Authorization: "Bearer ".concat(access_token), 120 | }; 121 | return [4 /*yield*/, (0, node_fetch_1.default)(GET_USER_DATA_URL, { 122 | method: "GET", 123 | headers: header, 124 | })]; 125 | case 1: 126 | res = _a.sent(); 127 | if (!res.ok) return [3 /*break*/, 3]; 128 | return [4 /*yield*/, res.json()]; 129 | case 2: return [2 /*return*/, _a.sent()]; 130 | case 3: throw new Error("".concat(BOLD_FG_RED, "Error while getting user data").concat(RESET_BOLD_FG_RED, "\n\t\t").concat(BOLD_FG_YELLOW, "Please be sure that you have access to user data on 42 api").concat(RESET_BOLD_FG_YELLOW)); 131 | } 132 | }); 133 | }); 134 | }; 135 | return Authenticator; 136 | }()); 137 | exports.default = Authenticator; 138 | -------------------------------------------------------------------------------- /dist/types/TokenErrorType.d.ts: -------------------------------------------------------------------------------- 1 | declare type TokenErrorType = { 2 | error: string; 3 | error_description: string; 4 | }; 5 | export default TokenErrorType; 6 | -------------------------------------------------------------------------------- /dist/types/TokenErrorType.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /dist/types/TokenType.d.ts: -------------------------------------------------------------------------------- 1 | declare type TokenType = { 2 | access_token: string; 3 | token_type: string; 4 | expires_in: number; 5 | refresh_token: string; 6 | scope: string; 7 | created_at: number; 8 | }; 9 | export default TokenType; 10 | -------------------------------------------------------------------------------- /dist/types/TokenType.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /dist/types/UserType.d.ts: -------------------------------------------------------------------------------- 1 | declare type UserType = { 2 | id: number; 3 | email: string; 4 | login: string; 5 | first_name: string; 6 | last_name: string; 7 | usual_full_name: string; 8 | usual_first_name: null; 9 | url: string; 10 | phone: string; 11 | displayname: string; 12 | image_url: string; 13 | new_image_url: string; 14 | 'staff?': boolean; 15 | correction_point: number; 16 | pool_month: string; 17 | pool_year: string; 18 | location: string; 19 | wallet: number; 20 | anonymize_date: string; 21 | data_erasure_date: string; 22 | created_at: string; 23 | updated_at: string; 24 | alumnized_at: null; 25 | 'alumni?': boolean; 26 | groups: [any]; 27 | cursus_users: [ 28 | { 29 | grade: null; 30 | level: number; 31 | skills: [any]; 32 | blackholed_at: null; 33 | id: number; 34 | begin_at: string; 35 | end_at: string; 36 | cursus_id: number; 37 | has_coalition: boolean; 38 | created_at: string; 39 | updated_at: string; 40 | user: [object]; 41 | cursus: [object]; 42 | } 43 | ]; 44 | projects_users: [ 45 | { 46 | id: number; 47 | occurrence: number; 48 | final_mark: null; 49 | status: string; 50 | 'validated?': null; 51 | current_team_id: number; 52 | project: [object]; 53 | cursus_ids: [any]; 54 | marked_at: null; 55 | marked: boolean; 56 | retriable_at: null; 57 | created_at: string; 58 | updated_at: string; 59 | } 60 | ]; 61 | languages_users: [ 62 | { 63 | id: number; 64 | language_id: number; 65 | user_id: number; 66 | position: number; 67 | created_at: string; 68 | } 69 | ]; 70 | achievements: [ 71 | { 72 | id: 41; 73 | name: string; 74 | description: string; 75 | tier: string; 76 | kind: string; 77 | visible: boolean; 78 | image: string; 79 | nbr_of_success: null; 80 | users_url: string; 81 | } 82 | ]; 83 | titles: [any]; 84 | titles_users: [any]; 85 | partnerships: [any]; 86 | patroned: [any]; 87 | patroning: [any]; 88 | expertises_users: [ 89 | { 90 | id: number; 91 | expertise_id: number; 92 | interested: boolean; 93 | value: number; 94 | contact_me: boolean; 95 | created_at: string; 96 | user_id: number; 97 | } 98 | ]; 99 | roles: [any]; 100 | campus: [ 101 | { 102 | id: number; 103 | name: string; 104 | time_zone: string; 105 | language: [object]; 106 | users_count: number; 107 | vogsphere_id: number; 108 | country: string; 109 | address: string; 110 | zip: string; 111 | city: string; 112 | website: string; 113 | facebook: string; 114 | twitter: string; 115 | active: boolean; 116 | public: boolean; 117 | email_extension: string; 118 | default_hidden_phone: boolean; 119 | } 120 | ]; 121 | campus_users: [ 122 | { 123 | id: number; 124 | user_id: number; 125 | campus_id: number; 126 | is_primary: boolean; 127 | created_at: string; 128 | updated_at: string; 129 | } 130 | ]; 131 | }; 132 | export default UserType; 133 | -------------------------------------------------------------------------------- /dist/types/UserType.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /example.ts: -------------------------------------------------------------------------------- 1 | import Authenticator from "api42client"; 2 | 3 | // you can see the attached screen shot to know where get this variables 4 | const UID = "98a139943caaa7645f98b077445f8e84de4cb23e7668fb010a01b9c0ed20b8a4"; 5 | const SECRET = "b34df710754fbe173bfd202cd0bfdf05fcdc4dda3f22b4d76459a2a1e1c35f"; 6 | const REDIRECT_URI = "http://localhost:3000"; 7 | 8 | // 42 authenticator instance 9 | var app = new Authenticator(UID, SECRET, REDIRECT_URI); 10 | 11 | // after send the user to 42 site to authorize the app [example of 42 site: https://api.intra.42.fr/oauth/authorize?client_id=98a139f98b077445f8e84de4cb23e7668fb010a01b9c0ed20b8a4&redirect_uri=http%3A%2F%2Flocalhost%3A3000&response_type=code] 12 | // 42 redirect the user to the REDIRECT_URI (in this example is: http://localhost:3000) with the code in query string 13 | // like that: http://localhost:3000/?code=7a0cb1a9c5b0fd31a0eb9c5f854fc2386b1edc2179f73c76904d65f5aae4e9bc 14 | // get the code from the query string (code=7a0cb1a9c5b0fd31a0eb9c5f854fc2386b1edc2179f73c76904d65f5aae4e9bc) 15 | // and give it to get_Access_token function like below 16 | var token = app.get_Access_token("1c18ed11e162f51607e07fb80477f2c85375db8209a3865634cfc5f0e0fedc1a"); 17 | 18 | token.then((data) => { 19 | // get the acces token of the user 20 | console.log("======================== auth user Data ========================="); 21 | console.log(data); 22 | console.log("========================= 42 user data =========================="); 23 | // get the user info from 42 api 24 | app.get_user_data(data.access_token).then((data) => { 25 | console.log(data); 26 | console.log("============================================================="); 27 | }); 28 | }).catch((err) => { 29 | console.log(err); 30 | }); 31 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api42client", 3 | "version": "2.1.2", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "api42client", 9 | "version": "2.1.2", 10 | "license": "MIT", 11 | "dependencies": { 12 | "node-fetch": "^2.6.1" 13 | }, 14 | "devDependencies": { 15 | "@types/node": "^18.7.16", 16 | "@types/node-fetch": "^2.6.2", 17 | "typescript": "^4.7.4" 18 | } 19 | }, 20 | "node_modules/@types/node": { 21 | "version": "18.7.16", 22 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz", 23 | "integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==", 24 | "dev": true 25 | }, 26 | "node_modules/@types/node-fetch": { 27 | "version": "2.6.2", 28 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", 29 | "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", 30 | "dev": true, 31 | "dependencies": { 32 | "@types/node": "*", 33 | "form-data": "^3.0.0" 34 | } 35 | }, 36 | "node_modules/asynckit": { 37 | "version": "0.4.0", 38 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 39 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 40 | "dev": true 41 | }, 42 | "node_modules/combined-stream": { 43 | "version": "1.0.8", 44 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 45 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 46 | "dev": true, 47 | "dependencies": { 48 | "delayed-stream": "~1.0.0" 49 | }, 50 | "engines": { 51 | "node": ">= 0.8" 52 | } 53 | }, 54 | "node_modules/delayed-stream": { 55 | "version": "1.0.0", 56 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 57 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 58 | "dev": true, 59 | "engines": { 60 | "node": ">=0.4.0" 61 | } 62 | }, 63 | "node_modules/form-data": { 64 | "version": "3.0.1", 65 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", 66 | "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", 67 | "dev": true, 68 | "dependencies": { 69 | "asynckit": "^0.4.0", 70 | "combined-stream": "^1.0.8", 71 | "mime-types": "^2.1.12" 72 | }, 73 | "engines": { 74 | "node": ">= 6" 75 | } 76 | }, 77 | "node_modules/mime-db": { 78 | "version": "1.52.0", 79 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 80 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 81 | "dev": true, 82 | "engines": { 83 | "node": ">= 0.6" 84 | } 85 | }, 86 | "node_modules/mime-types": { 87 | "version": "2.1.35", 88 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 89 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 90 | "dev": true, 91 | "dependencies": { 92 | "mime-db": "1.52.0" 93 | }, 94 | "engines": { 95 | "node": ">= 0.6" 96 | } 97 | }, 98 | "node_modules/node-fetch": { 99 | "version": "2.6.1", 100 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 101 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", 102 | "engines": { 103 | "node": "4.x || >=6.0.0" 104 | } 105 | }, 106 | "node_modules/typescript": { 107 | "version": "4.8.3", 108 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", 109 | "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", 110 | "dev": true, 111 | "bin": { 112 | "tsc": "bin/tsc", 113 | "tsserver": "bin/tsserver" 114 | }, 115 | "engines": { 116 | "node": ">=4.2.0" 117 | } 118 | } 119 | }, 120 | "dependencies": { 121 | "@types/node": { 122 | "version": "18.7.16", 123 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz", 124 | "integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==", 125 | "dev": true 126 | }, 127 | "@types/node-fetch": { 128 | "version": "2.6.2", 129 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", 130 | "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", 131 | "dev": true, 132 | "requires": { 133 | "@types/node": "*", 134 | "form-data": "^3.0.0" 135 | } 136 | }, 137 | "asynckit": { 138 | "version": "0.4.0", 139 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 140 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 141 | "dev": true 142 | }, 143 | "combined-stream": { 144 | "version": "1.0.8", 145 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 146 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 147 | "dev": true, 148 | "requires": { 149 | "delayed-stream": "~1.0.0" 150 | } 151 | }, 152 | "delayed-stream": { 153 | "version": "1.0.0", 154 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 155 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 156 | "dev": true 157 | }, 158 | "form-data": { 159 | "version": "3.0.1", 160 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", 161 | "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", 162 | "dev": true, 163 | "requires": { 164 | "asynckit": "^0.4.0", 165 | "combined-stream": "^1.0.8", 166 | "mime-types": "^2.1.12" 167 | } 168 | }, 169 | "mime-db": { 170 | "version": "1.52.0", 171 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 172 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 173 | "dev": true 174 | }, 175 | "mime-types": { 176 | "version": "2.1.35", 177 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 178 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 179 | "dev": true, 180 | "requires": { 181 | "mime-db": "1.52.0" 182 | } 183 | }, 184 | "node-fetch": { 185 | "version": "2.6.1", 186 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 187 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" 188 | }, 189 | "typescript": { 190 | "version": "4.8.3", 191 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", 192 | "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", 193 | "dev": true 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api42client", 3 | "version": "2.2.2", 4 | "scripts": { 5 | "build": "tsc" 6 | }, 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/kirwa-KO/API42Client" 10 | }, 11 | "keywords": [ 12 | "ft_transcendence", 13 | "intra42", 14 | "42api", 15 | "api42", 16 | "api42client", 17 | "connect 42 api", 18 | "connect to 42", 19 | "1337", 20 | "42", 21 | "node-fetch", 22 | "fetch 42 api", 23 | "fetch 42" 24 | ], 25 | "author": "kirwa-KO", 26 | "license": "MIT", 27 | "description": "API42Client is a class that help you interacte with 42 school api and get users data", 28 | "main": "dist/index.js", 29 | "types": "dist/index.d.ts", 30 | "files": [ 31 | "/dist" 32 | ], 33 | "devDependencies": { 34 | "@types/node": "^18.7.16", 35 | "@types/node-fetch": "^2.6.2", 36 | "typescript": "^4.7.4" 37 | }, 38 | "dependencies": { 39 | "node-fetch": "^2.6.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import TokenType from "./types/TokenType"; 2 | import TokenErrorType from "./types/TokenErrorType"; 3 | import UserType from "./types/UserType"; 4 | import nodeFetch from "node-fetch"; 5 | 6 | var GET_ACCESS_TOKEN_URL = "https://api.intra.42.fr/oauth/token"; 7 | var TEST_ACCESS_TOKEN = "https://api.intra.42.fr/oauth/token/info"; 8 | var GET_USER_DATA_URL = "https://api.intra.42.fr/v2/me"; 9 | 10 | const RESET_BOLD = "\u001b[22m" 11 | const BOLD = "\u001b[1m" 12 | const FG_GREEN = "\x1b[32m"; 13 | const RESET_COLOR = "\x1b[0m"; 14 | const FG_RED = "\x1b[31m"; 15 | const FG_YELLOW = "\x1b[33m"; 16 | 17 | const BOLD_FG_GREEN = `${BOLD}${FG_GREEN}`; 18 | const RESET_BOLD_FG_GREEN = `${RESET_BOLD}${RESET_COLOR}`; 19 | const BOLD_FG_RED = `${BOLD}${FG_RED}`; 20 | const RESET_BOLD_FG_RED = `${RESET_BOLD}${RESET_COLOR}`; 21 | const BOLD_FG_YELLOW = `${BOLD}${FG_YELLOW}`; 22 | const RESET_BOLD_FG_YELLOW = `${RESET_BOLD}${RESET_COLOR}`; 23 | 24 | 25 | var description = ` 26 | Authenticator 27 | 28 | The Authenticator make you connect to the 42 School API with the Authorization Code flow, 29 | this step for geting the Access-token That access token is used by the client to make API calls. 30 | 31 | Options: 32 | - "uid" : your 42 application's UID 33 | - "secret" : your 42 application's SECRET 34 | - "redirect_uri" : URL to which 42 will redirect the user after granting authorization 35 | `; 36 | 37 | class Authenticator { 38 | uid: string; 39 | secret: string; 40 | redirect_uri: string; 41 | 42 | constructor(uid: string, secret: string, redirect_uri: string) { 43 | this.uid = uid; 44 | this.secret = secret; 45 | this.redirect_uri = redirect_uri; 46 | } 47 | 48 | async get_Access_token( 49 | code: string 50 | ): Promise { 51 | var payload = { 52 | grant_type: "authorization_code", 53 | client_id: this.uid, 54 | client_secret: this.secret, 55 | code: code, 56 | redirect_uri: this.redirect_uri, 57 | }; 58 | var res = await nodeFetch(GET_ACCESS_TOKEN_URL, { 59 | method: "POST", 60 | body: JSON.stringify(payload), 61 | headers: { 62 | "Content-Type": "application/json", 63 | }, 64 | }); 65 | 66 | if (res.ok) { 67 | return await res.json(); 68 | } 69 | 70 | throw new Error(`${BOLD_FG_RED}Error while getting access token${RESET_BOLD_FG_RED} 71 | ${BOLD_FG_YELLOW}Please be sure that you use the right:${RESET_BOLD_FG_YELLOW} 72 | - uid, secret and redirect_uri 73 | - and the right code getted from the 42 API 74 | `); 75 | } 76 | 77 | async is_valid_token(access_token: string): Promise { 78 | const header = { 79 | Authorization: `Bearer ${access_token}`, 80 | }; 81 | 82 | var res = await nodeFetch(TEST_ACCESS_TOKEN, { 83 | method: "GET", 84 | headers: header, 85 | }); 86 | return res.status == 200 ? true : false; 87 | } 88 | 89 | async get_user_data(access_token: string): Promise { 90 | const header = { 91 | Authorization: `Bearer ${access_token}`, 92 | }; 93 | 94 | var res = await nodeFetch(GET_USER_DATA_URL, { 95 | method: "GET", 96 | headers: header, 97 | }); 98 | if (res.ok) { 99 | return await res.json(); 100 | } 101 | throw new Error(`${BOLD_FG_RED}Error while getting user data${RESET_BOLD_FG_RED} 102 | ${BOLD_FG_YELLOW}Please be sure that you have access to user data on 42 api${RESET_BOLD_FG_YELLOW}`); 103 | } 104 | } 105 | 106 | export default Authenticator; 107 | -------------------------------------------------------------------------------- /src/types/TokenErrorType.ts: -------------------------------------------------------------------------------- 1 | 2 | type TokenErrorType = { 3 | error: string; 4 | error_description: string; 5 | } 6 | 7 | export default TokenErrorType; -------------------------------------------------------------------------------- /src/types/TokenType.ts: -------------------------------------------------------------------------------- 1 | 2 | type TokenType = { 3 | access_token: string; 4 | token_type: string; 5 | expires_in: number; 6 | refresh_token: string; 7 | scope: string; 8 | created_at: number; 9 | } 10 | 11 | export default TokenType; -------------------------------------------------------------------------------- /src/types/UserType.ts: -------------------------------------------------------------------------------- 1 | type UserType = { 2 | id: number, 3 | email: string, 4 | login: string, 5 | first_name: string, 6 | last_name: string, 7 | usual_full_name: string, 8 | usual_first_name: null, 9 | url: string, 10 | phone: string, 11 | displayname: string, 12 | image_url: string, 13 | new_image_url: string, 14 | 'staff?': boolean, 15 | correction_point: number, 16 | pool_month: string, 17 | pool_year: string, 18 | location: string, 19 | wallet: number, 20 | anonymize_date: string, 21 | data_erasure_date: string, 22 | created_at: string, 23 | updated_at: string, 24 | alumnized_at: null, 25 | 'alumni?': boolean, 26 | groups: [any], 27 | cursus_users: [ 28 | { 29 | grade: null, 30 | level: number, 31 | skills: [any], 32 | blackholed_at: null, 33 | id: number, 34 | begin_at: string, 35 | end_at: string, 36 | cursus_id: number, 37 | has_coalition: boolean, 38 | created_at: string, 39 | updated_at: string, 40 | user: [object], 41 | cursus: [object] 42 | }, 43 | ], 44 | projects_users: [ 45 | { 46 | id: number, 47 | occurrence: number, 48 | final_mark: null, 49 | status: string, 50 | 'validated?': null, 51 | current_team_id: number, 52 | project: [object], 53 | cursus_ids: [any], 54 | marked_at: null, 55 | marked: boolean, 56 | retriable_at: null, 57 | created_at: string, 58 | updated_at: string 59 | }, 60 | ], 61 | languages_users: [ 62 | { 63 | id: number, 64 | language_id: number, 65 | user_id: number, 66 | position: number, 67 | created_at: string 68 | }, 69 | ], 70 | achievements: [ 71 | { 72 | id: 41, 73 | name: string, 74 | description: string, 75 | tier: string, 76 | kind: string, 77 | visible: boolean, 78 | image: string, 79 | nbr_of_success: null, 80 | users_url: string 81 | }, 82 | ], 83 | titles: [any], 84 | titles_users: [any], 85 | partnerships: [any], 86 | patroned: [any], 87 | patroning: [any], 88 | expertises_users: [ 89 | { 90 | id: number, 91 | expertise_id: number, 92 | interested: boolean, 93 | value: number, 94 | contact_me: boolean, 95 | created_at: string, 96 | user_id: number 97 | }, 98 | ], 99 | roles: [any], 100 | campus: [ 101 | { 102 | id: number, 103 | name: string, 104 | time_zone: string, 105 | language: [object], 106 | users_count: number, 107 | vogsphere_id: number, 108 | country: string, 109 | address: string, 110 | zip: string, 111 | city: string, 112 | website: string, 113 | facebook: string, 114 | twitter: string, 115 | active: boolean, 116 | public: boolean, 117 | email_extension: string, 118 | default_hidden_phone: boolean 119 | } 120 | ], 121 | campus_users: [ 122 | { 123 | id: number, 124 | user_id: number, 125 | campus_id: number, 126 | is_primary: boolean, 127 | created_at: string, 128 | updated_at: string 129 | } 130 | ] 131 | } 132 | 133 | export default UserType; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es2015", "dom"], 5 | "module": "commonjs", 6 | "declaration": true, 7 | "outDir": "./dist", 8 | "strict": true 9 | }, 10 | "include": ["src"], 11 | "exclude": ["node_modules"] 12 | } 13 | --------------------------------------------------------------------------------