diff --git a/NodeApp/.env.vault b/NodeApp/.env.vault
index 85a3476c23075cd04d21417852b32513acc4bca5..dfdcf927c6197bf63486a9fb84b97e47db10945c 100644
--- a/NodeApp/.env.vault
+++ b/NodeApp/.env.vault
@@ -4,11 +4,11 @@
 #/--------------------------------------------------/
 
 # development
-DOTENV_VAULT_DEVELOPMENT="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"
+DOTENV_VAULT_DEVELOPMENT="2wpLUByTGk2RJ96uWZuOt0Px8p3+Ixo02J0ec0EPcon4YXPoYVFVWCvDJoKbIOeqFIoNttc6mIZqg8pj90K+9WdH9C/b6bAx6Bd0dgJpALi0bpNY2ml2Ix4j4UScjuAiVZWbBtRBw3COQIGvZHx1yXgXkeectrKJdy90ItwIEodJQV4Y4vVbM/LM/0KOmt3toBJ0WLOqP9MewyrzpXM7yzS0hItBWzlGCV2If0NPS/7eqFFR3dfxqVE2a9Tx4eVa4jEiwj1rJE11I9N3D0u6x2iInYJ8yDENqVoV9iF4itpRKAUcTprN447+g4ScKWGHynj+wBM6mnXabZvMN+/iA6gC6ZXGsyt+FK3V/NSsUEMVNOQdRDnq2VZsqaV/2bPoRv5wgz3A4K55oaVl/jtMZgK86eGIPHtrH5UTjL2Zne9JwY8OV7YHF8ERQI/sFhzAqtYsCXg8q53CNreB5n5Hphenf8RsntYvMJkicV/osYqG9qqRtNk+ghP4utacFNki1BomKFoDIOR4fN3HwBxdvLqCaJ3RZnkyMfWQuxfMMFZFXi3sOZnvfmDfhqBDQniqzVkp4oZ9Jndqko05faUdYlSAO3SQX8DCutAB7pUGltiX5hHjbPk/i6Jl1HeAvq1cCmIUamVSM2actfFcmT05X31aLon1FNNZvyNlZuv5mFsK3ZF+U5iWvKgWqpY01xhaZNlLW0Bnmr3QwdbIR+DnGCfUGitIf3o9VkOTF3ElEUsVRldqA29jgXySfnBzyZVQ2TeuCzwVIEyfLquENgYeAN1/cEJqCYcEmqXiCWvPx2xFKQxfcQxxKFupabHTmbBJhblnF1Id4CGssKt8OhJbhRkydoTGkefgUxm5ioq5yKW/G5oCpE4FP/PdFKAiwPK2Hbl22hfMGXXWCEoB56+QRXK0oDAGhNNNrjhVe93bZOqUSdPQdNIp4iC2itGicGN7ps9yCScWqlv5dSUac+633YmEW6sfEbn477oz6iZZy+d58aRU3yr+Gj5ve34RtuQ39GlJ3PrxhTgl+xuKCyJgzzdGXNlpO/roZrpNVqGCpchQY8n6ahuIsbwMhPH2psxM25duu8DMNJWGGGX0hF4C6bKusQhd04YSiLWCJDYdB7OJQ+Wc/Mlcuz6/0+LOp03QgqvUm5hOqQ9Tma6ynEVpWGclSzFoHCYWNr5yneBTv28NoFU6R91+GNL26mP7CUXswl+8e7Rb1VdFK7t/CgHVlSWxeoOJJlJKSM1rYJ4NU2KKnq1oL1Asqunus7kxKEgq2rY2TIo1zYoEkEe0QRGJ/OEaPBLNGZB+PrtyxAPPi6j83aYQ9uwARO35iJVEPTIowBFgudu6iCW+kSeF40YSbNyEi9asDiWXL6oYk5VkC7lHrke+m8QZrQZjS2iK1mSMHh62SElMrWBhGpck0Qzoi5/FjvLYhWEd3q626D+d5M6MVaEjalr1FOuq1NnR2SbpwqzoGMffwgRtNhh7mhF/uh/3W886R005YB4vwYZtFEPEGUJitG9m3+b67mGAKK2qq98xLwA8RdFGoItI84Fojg9Z3LEcJ0YYdb6vnwqPVxwUOpCBsiS65i5fXJxl78A2Sh1IRleemjts3kRVIlI0TfagrwPVewmZ3AC2USFAmrFaO7beE0hJ7hRDKV33eZgW8t2lIyRzXcA8IRANhZrenlO1gFn/uTq2b93Y"
 
 # production
-DOTENV_VAULT_PRODUCTION="wpkU0o0laCd2mANVdd+8ji6Q8mF1lczuMTNOxZhc+s/ISsa95JvSdUONbjn0tyaGUsXO7XH+YDZcTFP/RZr5ZDDki0YFhKgZbnwWHAXfYcU+U5+y6nT3ONMf1cApnS+iZuNLc3WgU13IT4ShW9zIv9aLibservDhVBXInYW+BPGi/KMUhh1iSTbJXPU/w6A+eLmjXQQnaY4F+eVfIk9H9175n5NxmeZNqkPmocqP8ZR21Z6FvugYaNGAC0Q3Rz1Y3oS76UUeIYqPdwPTO5AJN/3DY9f/9J2iSRpW4hp12KKl/kaZVRSV2Je++whIvdwQASyQ0vpw4wl+YdTT+M7voa7hX6NpS6KnHBGrm+C+rdXmEzZY7rvzREMWvIUlqP1GQrG4CjVOeNXejAo6on/ZNe+zBCYabmdOY/ZtdECl17mfVDPuvaJhfKbLHGA2Hs9v+03xfvxBBghB9lDigz1YM/EdrjhbKnbPPpKFz0JgabBZIv5e91zVnGGne1T6opzRujiJnFI+w0S9wvYX8i4QdFimM9R8MX6LTkWBjzFGYXFS+4jdUsAwc0vZXn1zjBImdzVUVMdnibXKw4MoKxS2ddrmoXkpTV6IIIsKdetfhax65WA6GoVDl1pQVgxIa9Vwkgolu/7EF/RKuCHhclpJA2xvvm8UtqfgMFvaTlcj+nhb256s/vBS62eqHpQTmO+mU3+gfTrbz3bKV+LNmge5OqedHIQusqxKewCdZND67uMKa3MYgeQG3UdPlIYw0Twgvme7LPopj5Prs/6pc7YKH9yelDNc+NR2Huvf3ooRb4lEVl3VrMhsiPl+E+RLGR1jv6yJ3aTlZv/4kyxTWn5aDSz6AF+aiZph/ZLQaDBcN5VDxHq9jrFOrxoSvcp1IP7MI3IvD3lPVCQXVl/HOzfnQWF8PcSxcr96Td57KhUPxyvyUy01b0qYLDEM9FgVe2YytgRLIh2sxv3n7fbYhDReD2jnGBMNCAE/mg2Gc+muTiqTs5RPpvgtZVAnhvLnz/o2Pgc7gI30zluoCK/ZkkCZOF/+ukL+I2adyd2+/LJrX+hjyvxcdDHP1LcGhO/xsPBj7fT49/j87aF8K4M5RYEpXvh+fmBqCd4uPd8LBbffa2dNrxJgc0DRbS8lUoN8FUVe680lnZ8PZW49bGC9qeIIuH1uBr2DWo4/ufoHyDUKp7x4LxJYGY/7Qn2S/gBDG3CnomC8clYO5ud3UYJWqEecvqiminPFj2BaNzEgNuiIq4wW+KrkQK0Q2HKY5Qh8ryh16SxIsMqfaKNj74DFlEjf/C94IJw2IPzDFTBq1mas3odGZ76pwD0ryI6jGta2My4zW5Ld8NhHTJGNXZ/tqYIAVscdKvvXzpY8xkDBiRHm21AmjWRsO9S2GatBtEXVKQ0+YFCcfPl3754jfSt7KBz5HrRNPAjWPV36MBH5XlbcASfIRpjhD+Ks6N3bLEx3u7KEQum1nwZZM9Hk/3IHBoqndVRgHqGO4BNYumzUuWArN+JUVuRXCloPiFGYxZaoipG3RJE55eLvNdjsUMq1nM+zkdxs2gu2mqj1W8zFCvWdrAVEvrO91fzAmlVLs/2Tj1nj5T91Cxrz5yu1Qwb/sqd3NQBeETnTRWYydp88WtUvt8mmSfSkKw49txABlLzUQXRgMprd5SjG/yDDoxv/w0S/wa4gqhH+lITbmVqIpiD+9fmlO9QG1x9glpihuQi4/uxoiHnHJC1+a3XnGfsgztaVHXfk+vjA+WAI3xBOiMLx+5IjeR9QhP5dJaEqVsOEeziIdpt0DZErl1zd0vgq77pIe3qpqNj5qcbkFwWOy5ZTriedZ1nrOse48jTreqSTH2QWJ9Mp7OYxChl0WHIjNa0TwjfDvRPF0eFu3n6wbheX058jgyXBjbCuFSkKydGRbPLIWf9S7gOSqybBClQeDdUjaA5v+7tj/VNRcdUEATrZGrdyt3AV6BKuu+OOnc7KYQwNvDq0jfJSHaKWAJi44XT5mwCyvP5BAQVaH43QVy3DvZnpLie0"
+DOTENV_VAULT_PRODUCTION="ekKd8Oyzl+sLX1qB2m8q2FThDhqowPd+7bdJyREYUvT9NPni7o+wgdP1gd8nErFPKfClHm+kGNft18WxstISsMMt51T2zrdaDO0d/DGJcu7oq8c9HChJYsSeVoM+FVJYToOn1LKrgJywQPlB0krHHAYWo1vi6gnWCPb2GMU2RstBPKjQXdToLkk7u4YlNOROksMHG/n0u0n5opNFT0qTQcYeYgaTrY92I526rS/xEfJsH2gJsyPnrtNogZipwRd6ujP9fXKmS3RrQ5Sd9aadX/CqyzjchOCiUZciVsZobBuS7/RIOPWQtWmf/tXGXBZX7llUWTDOl8tryTHOIl21WmA2RxOjJjIPK8yZfn9nSNDRUD7Hd+wSgweMNHbtmbdbgpumrw0LrYWRuJIvu6sOGkLjc7zua5uxH0frEWn1h5Rjwx8OsgReEBxeoYfNPb96OF6+sayE9JitwsmznWone1GArcrrBv+aJvzr9AnwA7tq44e1WFVE/fhDaTwWraOQF0hmmA6pDJgE1gPgOiXVtgLV3J6DvPGfS8ax0ug+S8u4Pi/87vhcHud43N+CuVr5giJHSDAp8m3LCntEzF9lvkuNH57M3DHBr5YWHsvpYkmo4SIWCmVqRfsIRTeH8gCoAkxnd9PwDmJ7zJzucGEfTgzNgGavc6HHEpaW3pp2jpidp1iEmxtwbBM25umZ7P/emeztPxzPCxnAYsXov/2d6LsMCF8eNszwR0+W7lFV+JM8QrS9/KwHD9HPYNYWAJp06ludLcCKRxIbqLECZpKxjrJG9pY/7TAiuUmxiwm8FkbNYWavRoDPTcxfqTO2a76M1GfKIF+xWzqjsY7r1FkUAwCBr9CmW9ZpAx779grIyo6e7MptGIm0QHr4iH8UXFYU9S3kN/AoJUD5eTJVCa+17+hj+iyDUAcPVTDW9oJRjdZ73aZ86oui8n/1f42MkLChJJ1umxJSlvvzvH27FHWM/JHwYwLgIWC/8p/tt/Zy80XQbk8oz7nvp0C3un0lwrLJwazI4MW3Sj0E/QiKKvowX5JSOFbCOvoBreHU+U9n0veGXKqROrK2IcS2e0zExv14emiPnNrPNnoDcETwC0hGFhkJoJUiFXjnn7WAFmdMBrdxQKSelYPQ/8wAWjhgA33n1o+PkMnvkY1Yd4h8ua1WXWW1khr7nFkPv5VYDyzRWmba8Fd5JWrydDVg7QO6SYagvTdSuj6Hahe7NPL8jjaj3MNXP9yyW98tBMTm7xe8bi+kK1ZoZOcSh8DxjGFwUcQlru2RMX65zEW0q6YRNJIBnQfP7f1737wnoyWFFyKWfjGFI1n5dWycOwZn7+is1rVFPLbx45vNARRYaoJJwGKhqOdTlwM6WBeaJyYUCi6WfQ7Cfl+uHIPBvRC5zMH1Ac+wbvqqdIBc3H9XuH/30yXvM5SBCzDumzl9HY50QLUz5Q/lLrqlcllIfjdmWCuWes19oT1/Vskj5VXt7cDfWTXNPePFyECsrpNukh4SnNOfobIeNKo5+FD33hKWpSC/zTP+N0nKF/OWME9DzHO749KNweOh+W8wNZf3FKNiKARTWoM7lXnyyIY1ld7nWzpsIDtbGkncidk8cbTCmXFVQmxhYqF0DP9xCHqKKfrVdaMdirj58mOIS1KZCj9RUYYaL2ct8WhSEuNIh+Oln/UBo/6wR5+Q2itfBt4359eWb0RGl8at0pvq6OVy4bmtWbaXrW/8JwdI/QxHt9Lw9g=="
 
 # test
-DOTENV_VAULT_TEST="CYDEOpA8aIlJs245eFTFon8fcioqqLopkdOco1dRb5g70jfXSvgOJQ5GYuFFGOPfZkv0Q5yTHvABPiUzMP8RS0m2x+88BKpfd2TS/9ojTq/UASfOJH0/OaR2Pfj72nKqKN3PuAE6Gf0GQsjzypa25B8z0b3eRbaV/wvCxSbV+Y2F4kkw/+mm9TtYtG3oWFHyBzcAD/zGyFcXqmRDi2tIw0IHEWzD4emIS1rJDK/8Y85xILSrALAtfyPr+a2tvSNapg8kH1dv+BG5DIZBz/8xERxJQNO68altEkpsDEoue23rGEReP3gcIfF0E7/y55PEXkPUQl2RQNXIPW9DdMa0tb94ToHiOgMmOxo6oW+liIShD6ERTZIIzcA4yD+jEEFP739evtfouEHw5SeGVp++EjWN4PwB9qmow6mNgDDQyFolxzlbRvfsWQEvTGe0urXzthE+0THbHHX128XUS3NwVWLLTZEECZRvz9ZeiuAPadKoqCdydDLg5s+ufajlmw0fFJVhMQc+AP533ttlHC2vT4xVjjN59Z2yE94kap3i4HtyGqKMq7bFJWAiLT4B615xrg9zZUarlE1qM7ZqXsGpyU3kyAm+/wf4/s2hGYl8uK/ff5rmXU4X+9gobmuV77H07iuWUJESbg3dl1NQK0X4y1zA9EWcU3OB7LFrwi3ydzgi84Aq/tvOnhxn0n1PRvMwqsX4qVj3JCynUSAM3RA8ukO9RL7CcMjNnNvHi58UhLUJVCJLyZ4MS3Hcx+GdnpQ92KQvIEUFtwcLX9SaEQSRBdRJ+Knxq711E2pJrcv1uHMi7fJbaBuPsnP/ntkcWrxqmp7EqcHl29bGzOVs9js0sjlBpnW9RjvJ0AIug3ze2JzG1qoT42jSWjVVNiVTAGGPOXIFqrzx5eaTYt2bE0oWNlQCY+0bJAPqtpBJWX2sxnnuKOtYjOYXMx7uz92WJDdtmzvXZ5ymOOs0Ye7RxxBvZUSEyBws1MCP39VuOJcMidUfQGLMhiNv7EkVaPudwYQ1pD8Fvav/oQQmRNOiIo5UrbC7dZ9fd/RrS+65mDhCxHj7nni7O959reDd1y0xo+zKmD64JChJVTWN2/YyhFdqieGL8Lmtz3Z9rkigch3q4HnpVfFJmCcBGjP/KenftIW2AWU9LMHUwwEggLTU4XyO5AhhwFzzWaYWrUqxbVxhS0gsTYw/2lm+PWXFMBI7FQgax2Y9sp/eMeKGjgkykmyftqhHfmet3C7ALzdbygpkERkq9JjXQdigtmgSP1lFxxf8LkmSdWYQqHNvrTeXDJyQdL3m2m9o0zUMBnDjtd64LnslWjUBPk7uLARd3cKIK4lPGP66+jgvMJKoGJTjFcD67xko++M+/2R/ip919uTxJ+/y1mtJXFnSL/FA4jl2UsU3YaiOISO726Zv1l4AuoKfRq6x1KlfJKemh2MQVdXwXIqvqfvOIHz6/P3Eie4cwt00WDV1GbVQgR4FEAT6uQxxMaSXTGJwi4g48TprsKN+zWmmCXzAF/Zmpy9O8GNrW9of8WY6hGe9ZpMhANhTSOIH2ey3Zenkl4ZoYKZ9ywbK6db0pSFPr9SXdzzPVOeriQzQ57ij0YX7YIZJA3YROqMRRQ+xnQTnxQlxRGTJPd5abU01KVNWy9GVu/Win7wQuWg0QeDWEIS5ga3tNb4txtWzyFam9RHVPA76YjOUIgL9NMrHq4t5iE3HAr1QU4pMZ5BEeFA/nqY7kO8rNGPYrwe41cd5RcwBajPxyGH0HGxT8ovd3U2vN6fpje6NuB4e3Uz8Go2CP4U5x/b29MoR245iPjtzhn0Q/AhIMr5MVEN8Zt8DcLBtxo2E11KQMHqXuadsqT/mS65PlshVeqgITl34IIV/tf8flC143FLQNlNECqgHgE9GLEJvuTKSHLFhDC6pHstGLEyPe8gtMikN4DlyqdZ/pqV4hhNG1E+jeL3x"
+DOTENV_VAULT_TEST="b5ToqL+fFVc56n51iF2pk5fuWvjqEmTNGD7DGEzVP71lQ7KuswE3VEOCDTmNUtxpiiauF7t1/kBAozDIdSRngJz3CDPLEU61ioKZnEI9WB0EXTMyBX+ih7FiZMm+G9Qa0cVwA+g1oP2LY8TACjSxRjb0wYKTLRz6pn2J2hEqs1Fxp0UU3/zAnuIlnHwGq5gpL3S2gu5DtJULJT4uz4eI1UHI01p56R1dgW+KSor9tMHMf0PvBwa3MK3sb2EkFYf6Ith6STTXrNw49dJgnGAK7O9+V7nKiPtmC9udifUNH/i/zpDNggENiatEt6476Z+8Au0fgX+HUzC/+dlGAdDoVWwLGqGTnKbH386uuBuWtKdY+/Yvsjd7tHQY+90sv0zya28cd3daIs+ZR2YNPUbOWJ14PPkVijJs3A+MuO7WxUpGtqG4U3LL96T0tShRgf9RDeb2/d5m+YlcAYeA08cva+SBIKhPZi7HhlfY5J0sK+pNVWEZIF5hET7hZg6N2aeY1WDrKAEiayaIK5ndSBM5yiVlPmMiQkEPBDZ9U6upLhpKK57lARAYXAzkuEVRDuFuha+fcfwBsM4EvejdIG67Cu4J1IG3eq0eBybo+4jaP8p0MRgp8kwgsNjwCFPNX0H+mVH9i1t7Z3eDfocHM1WhoOEWIAPxRyj7PdrWA6StTn1HdY5SP0ytB0WSh0H+lEJ1G5uRy9K/sN8rmmGzmah10Ti+2gvrYFjyRdaZwTJXtyWN6oVZY75X3KQx+Fb2peJwTpA3vZBpo6CGUkDItO8lvxkkFKkVy1IHIyUYBSRLhuE2QAseG3q+QE9UF2cYAYtonFr+oTFqch0eDca7e4m8QsXmAC1t+opoTbpPgwyth29WHK5OARNAL+hSsGj6EMgGpJuNMFZVHhQ4KIr1JSh2MjbnYkTdWTCpLbOKEbH/40LKdKHSzg3IMQnXAl0+rtIcDUCpPXrM7miVW6+dvy9kCp4HM9+7kuHj02vDL+I9GOXsmYRXTq99G/FdRj4rKxd5/kR38fzUjuNHBuUFofqmvhGFsP6bdeNfOfKoonGwZ/9cogC9dcPysvdL2pHMZ8VWm5yaP4yzMOoo+w6VgNK93qP/NyM28b6ouUO8t3gIfnn8lKEM/vZbmSXM51eG5hD+Yxjadm0cAuDnO5R3KjsjlodtCzlAel+Gmvc+X/8jWBm6ZP0x+28rtMjStpbgt/xnoDTV1uyAFxNi72hBhbMCV8gpXtZqI9QOylBxzhWl8D8HtoS0JCxp7yVOzZK3kbQ4BFxyl+MJKElRrdOt7lhXKej30T75W+RRLujlhdI6pTVadMLDltmGU2j0YBinD2uDe1EFL1QGKTCycFLHtYTFJSLPoTCWlBO4KZNTopuWN2v4aaIDQAzs9LEhiWrA9ENhS3fBykBbE2DWY0XczeMvEEALnunrPdFTdIy9SYW2mkZwviuwPmHDbferqT/7iPnCdZY1OsT52xKr/dCJMXpxHA01yB3n+ewVtbl6/WU9Oe3coPPHBd5PctvzGhcTZ9w6DkHHzTmbHIfEBYejzc+D3y1A5VI02EAFWRiboJOht0meX5KKpPQWzOt5D2WOtdF2WkTe+Ge5sA+3w349xF9azVYuHw5qouf2+xzhyavst+4/KF6KKQCWwCU="
 
diff --git a/NodeApp/src/app.ts b/NodeApp/src/app.ts
index 3228486f8e0531c4a9867dbb315ff1cfc21bbdc2..072d4d8c4a72bfd3dfd9683c6e1e5f5883b1b225 100644
--- a/NodeApp/src/app.ts
+++ b/NodeApp/src/app.ts
@@ -1,10 +1,23 @@
 // ATTENTION : This line MUST be the first of this file
 import './init.js';
-import CommanderApp from './commander/CommanderApp.js';
-import HttpManager  from './managers/HttpManager.js';
+import CommanderApp           from './commander/CommanderApp.js';
+import HttpManager            from './managers/HttpManager.js';
+import Config                 from './config/Config';
+import ConfigFiles            from './config/ConfigFiles';
+import DojoBackendManager     from './managers/DojoBackendManager';
+import SharedAssignmentHelper from './shared/helpers/Dojo/SharedAssignmentHelper';
 
 
-HttpManager.registerAxiosInterceptor();
+(async () => {
+    ConfigFiles.init();
 
+    await Config.init(await DojoBackendManager.getApiUrl());
 
-(new CommanderApp()).parse();
\ No newline at end of file
+    SharedAssignmentHelper.init(Config.gitlabManager);
+
+    HttpManager.registerAxiosInterceptor();
+
+    const commanderApp = new CommanderApp();
+    await commanderApp.init();
+    commanderApp.parse();
+})();
\ No newline at end of file
diff --git a/NodeApp/src/commander/CommanderApp.ts b/NodeApp/src/commander/CommanderApp.ts
index 30e9cfe3ba8195af46113d33add1ecff63aa2550..685da94009efb76da7109860cc2d7430466073b0 100644
--- a/NodeApp/src/commander/CommanderApp.ts
+++ b/NodeApp/src/commander/CommanderApp.ts
@@ -1,19 +1,20 @@
 import { Command, Option } from 'commander';
-import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig.js';
 import AssignmentCommand   from './assignment/AssignmentCommand.js';
 import ExerciseCommand     from './exercise/ExerciseCommand.js';
 import SharedConfig        from '../shared/config/SharedConfig.js';
 import boxen               from 'boxen';
-import { stateConfigFile } from '../config/ConfigFiles.js';
 import semver              from 'semver/preload.js';
 import { version }         from '../config/Version.js';
-import Config              from '../config/Config.js';
 import CompletionCommand   from './completion/CompletionCommand.js';
 import AuthCommand         from './auth/AuthCommand.js';
 import SessionCommand      from './auth/SessionCommand.js';
 import UpgradeCommand      from './UpgradeCommand.js';
 import TextStyle           from '../types/TextStyle.js';
 import TagCommand          from './tag/TagCommand';
+import ConfigFiles         from '../config/ConfigFiles';
+import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig';
+import Config              from '../config/Config';
+import SettingsCommand     from './settings/SettingsCommand';
 
 
 class CommanderApp {
@@ -33,7 +34,7 @@ class CommanderApp {
         }
     }
 
-    constructor() {
+    public async init() {
         this.program
             .name('dojo')
             .description('CLI of the Dojo application')
@@ -95,8 +96,8 @@ ${ TextStyle.CODE(' dojo upgrade ') }`, {
 
     private informNewVersion() {
         if ( SharedConfig.production ) {
-            const latestDojoCliVersion = stateConfigFile.getParam('latestDojoCliVersion') as string | null || '0.0.0';
-            const latestDojoCliVersionNotification = stateConfigFile.getParam('latestDojoCliVersionNotification') as number | null || 0;
+            const latestDojoCliVersion = ConfigFiles.stateConfigFile.getParam('latestDojoCliVersion') as string | null || '0.0.0';
+            const latestDojoCliVersionNotification = ConfigFiles.stateConfigFile.getParam('latestDojoCliVersionNotification') as number | null || 0;
             if ( semver.lt(version as string, latestDojoCliVersion) && (new Date()).getTime() - latestDojoCliVersionNotification >= Config.versionUpdateInformationPeriodHours * 60 * 60 * 1000 ) {
                 console.log(boxen(`The ${ latestDojoCliVersion } version of the DojoCLI is available.
 You can upgrade the DojoCLI by executing this command: 
@@ -109,7 +110,7 @@ ${ TextStyle.CODE(' dojo upgrade ') }`, {
                     padding       : 1,
                     textAlignment : 'left'
                 }));
-                stateConfigFile.setParam('latestDojoCliVersionNotification', (new Date()).getTime());
+                ConfigFiles.stateConfigFile.setParam('latestDojoCliVersionNotification', (new Date()).getTime());
             }
         }
     }
@@ -122,6 +123,7 @@ ${ TextStyle.CODE(' dojo upgrade ') }`, {
         TagCommand.registerOnCommand(this.program);
         CompletionCommand.registerOnCommand(this.program);
         UpgradeCommand.registerOnCommand(this.program);
+        SettingsCommand.registerOnCommand(this.program);
     }
 }
 
diff --git a/NodeApp/src/commander/UpgradeCommand.ts b/NodeApp/src/commander/UpgradeCommand.ts
index 18a96ab9716fb49cdb63286c643e3d65f533d79a..653fdc8051207a4f1a6e590d07e484b1d41ef6d8 100644
--- a/NodeApp/src/commander/UpgradeCommand.ts
+++ b/NodeApp/src/commander/UpgradeCommand.ts
@@ -1,9 +1,9 @@
 import CommanderCommand from './CommanderCommand.js';
 import ora              from 'ora';
-import Config           from '../config/Config.js';
 import TextStyle        from '../types/TextStyle.js';
 import os               from 'os';
 import { spawn }        from 'child_process';
+import Config           from '../config/Config';
 
 
 class UpgradeCommand extends CommanderCommand {
@@ -18,7 +18,7 @@ class UpgradeCommand extends CommanderCommand {
 
     private displayInstructions(upgradeCommand: string, preAlpha: boolean) {
         upgradeCommand = TextStyle.CODE(` ${ upgradeCommand } `);
-        
+
         console.log(TextStyle.BLOCK(`You can upgrade DojoCLI on ${ os.platform() === 'darwin' ? 'macOS' : 'Linux' }:`));
         ora().start().info(`By executing this command: ${ upgradeCommand }`);
         console.log('or');
diff --git a/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts b/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts
index 86a5bc585c2f68c833fb8b3618792da99fa9b439..d5cab1979c72b38b08b4ce6e6e0e2c64e7ca879a 100644
--- a/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts
+++ b/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts
@@ -6,7 +6,7 @@ import DojoBackendManager from '../../../managers/DojoBackendManager.js';
 import Toolbox            from '../../../shared/helpers/Toolbox.js';
 import * as Gitlab        from '@gitbeaker/rest';
 import TextStyle          from '../../../types/TextStyle.js';
-import GitlabManager      from '../../../managers/GitlabManager.js';
+import Config             from '../../../config/Config';
 
 
 type CommandOptions = { name: string, template?: string, members_id?: Array<number>, members_username?: Array<string>, clone?: string | boolean }
@@ -35,7 +35,7 @@ class AssignmentCreateCommand extends CommanderCommand {
 
         await AccessesHelper.checkTeachingStaff();
 
-        this.members = await GitlabManager.fetchMembers(options);
+        this.members = await Config.gitlabManager.fetchMembers(options);
         if ( !this.members ) {
             throw new Error();
         }
@@ -82,7 +82,7 @@ class AssignmentCreateCommand extends CommanderCommand {
         if ( options.clone ) {
             console.log(TextStyle.BLOCK('Please wait while we are cloning the repository...'));
 
-            await GitlabManager.cloneRepository(options.clone, this.assignment.gitlabCreationInfo.ssh_url_to_repo, undefined, true, 0);
+            await Config.gitlabManager.cloneRepository(options.clone, this.assignment.gitlabCreationInfo.ssh_url_to_repo, undefined, true, 0);
         }
     }
 
diff --git a/NodeApp/src/commander/auth/subcommands/AuthTestCommand.ts b/NodeApp/src/commander/auth/subcommands/AuthTestCommand.ts
index e2e9d67ef39b3eeab6189f28272ae9abee1ccc3c..d75bc6268e5334376c584d2706239ba3c42bbf82 100644
--- a/NodeApp/src/commander/auth/subcommands/AuthTestCommand.ts
+++ b/NodeApp/src/commander/auth/subcommands/AuthTestCommand.ts
@@ -1,6 +1,6 @@
 import CommanderCommand from '../../CommanderCommand.js';
 import SessionManager   from '../../../managers/SessionManager.js';
-import GitlabManager    from '../../../managers/GitlabManager.js';
+import Config           from '../../../config/Config';
 
 
 class AuthTestCommand extends CommanderCommand {
@@ -14,7 +14,7 @@ class AuthTestCommand extends CommanderCommand {
 
     protected async commandAction(): Promise<void> {
         await SessionManager.testSession();
-        await GitlabManager.testToken();
+        await Config.gitlabManager.testToken();
     }
 }
 
diff --git a/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts b/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts
index 650d1504f725c7db60d9cb5b45140838d21d5300..dd3d066619e899be647a5a267e74492058934250 100644
--- a/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts
+++ b/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts
@@ -1,12 +1,12 @@
 import CommanderCommand   from '../../CommanderCommand.js';
 import ora                from 'ora';
 import DojoBackendManager from '../../../managers/DojoBackendManager.js';
-import Config             from '../../../config/Config.js';
 import Assignment         from '../../../sharedByClients/models/Assignment.js';
 import inquirer           from 'inquirer';
 import open               from 'open';
 import chalk              from 'chalk';
 import TextStyle          from '../../../types/TextStyle.js';
+import Config             from '../../../config/Config';
 
 
 type CorrectionResume = { name: string, value: string }
diff --git a/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts b/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts
index 3db1510582c5927fcf506ac6acc360f04548aa8c..a94277533e02a8528ee69e4951f7a827a1a86f2a 100644
--- a/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts
+++ b/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts
@@ -6,8 +6,8 @@ import Assignment         from '../../../sharedByClients/models/Assignment.js';
 import Exercise           from '../../../sharedByClients/models/Exercise.js';
 import * as Gitlab        from '@gitbeaker/rest';
 import TextStyle          from '../../../types/TextStyle.js';
-import GitlabManager      from '../../../managers/GitlabManager.js';
 import inquirer           from 'inquirer';
+import Config             from '../../../config/Config';
 
 
 type CommandOptions = { assignment: string, members_id?: Array<number>, members_username?: Array<string>, clone?: string | boolean }
@@ -35,7 +35,7 @@ class ExerciseCreateCommand extends CommanderCommand {
 
         await AccessesHelper.checkStudent();
 
-        this.members = await GitlabManager.fetchMembers(options);
+        this.members = await Config.gitlabManager.fetchMembers(options);
         if ( !this.members ) {
             throw new Error();
         }
@@ -116,7 +116,7 @@ class ExerciseCreateCommand extends CommanderCommand {
         if ( options.clone ) {
             console.log(TextStyle.BLOCK('Please wait while we are cloning the repository...'));
 
-            await GitlabManager.cloneRepository(options.clone, this.exercise.gitlabCreationInfo.ssh_url_to_repo, `DojoExercise_${ this.exercise.assignmentName }`, true, 0);
+            await Config.gitlabManager.cloneRepository(options.clone, this.exercise.gitlabCreationInfo.ssh_url_to_repo, `DojoExercise_${ this.exercise.assignmentName }`, true, 0);
         }
     }
 
diff --git a/NodeApp/src/commander/settings/SettingsCommand.ts b/NodeApp/src/commander/settings/SettingsCommand.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6fbcb6e7a5cb0b79c7432975a9b2d12fa6a2db98
--- /dev/null
+++ b/NodeApp/src/commander/settings/SettingsCommand.ts
@@ -0,0 +1,23 @@
+import CommanderCommand   from '../CommanderCommand.js';
+import SettingsApiCommand from './subcommands/SettingsApiCommand';
+
+
+class SettingsCommand extends CommanderCommand {
+    protected commandName: string = 'settings';
+
+    protected defineCommand() {
+        this.command
+            .description('manage Dojo settings');
+    }
+
+    protected defineSubCommands() {
+        SettingsApiCommand.registerOnCommand(this.command);
+    }
+
+    protected async commandAction(): Promise<void> {
+        // No action
+    }
+}
+
+
+export default new SettingsCommand();
\ No newline at end of file
diff --git a/NodeApp/src/commander/settings/subcommands/SettingsApiCommand.ts b/NodeApp/src/commander/settings/subcommands/SettingsApiCommand.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b8602c0d50203a4983f102368ef1a17ec3332482
--- /dev/null
+++ b/NodeApp/src/commander/settings/subcommands/SettingsApiCommand.ts
@@ -0,0 +1,29 @@
+import CommanderCommand   from '../../CommanderCommand.js';
+import DojoBackendManager from '../../../managers/DojoBackendManager';
+import { Option }         from 'commander';
+
+
+class SettingsApiCommand extends CommanderCommand {
+    protected commandName: string = 'api';
+
+    protected defineCommand() {
+        this.command
+            .description('change Dojo API URL')
+            .option('-u, --url <string>', 'specify the url of the Dojo API')
+            .addOption(new Option('--clean', 'clean the Dojo API settings').conflicts('url'))
+            .action(this.commandAction.bind(this));
+    }
+
+    protected async commandAction(options: { url: string, clean: boolean }): Promise<void> {
+        if ( options.clean ) {
+            await DojoBackendManager.cleanApiUrl();
+        } else if ( options.url ) {
+            await DojoBackendManager.setApiUrl(options.url);
+        } else {
+            await DojoBackendManager.askApiUrl(true);
+        }
+    }
+}
+
+
+export default new SettingsApiCommand();
\ No newline at end of file
diff --git a/NodeApp/src/config/Config.ts b/NodeApp/src/config/Config.ts
index 615a36942e83d11b0e63d3de6a89e8ff74944d5c..ec06f03df69177f359825ba44894ba81fa214995 100644
--- a/NodeApp/src/config/Config.ts
+++ b/NodeApp/src/config/Config.ts
@@ -1,19 +1,18 @@
-import getAppDataPath from 'appdata-path';
+import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig';
+import GitlabManager       from '../managers/GitlabManager';
 
 
 class Config {
-    public readonly localConfig: {
-        folder: string; sessionFile: string; stateFile: string;
-    };
+    public gitlabManager!: GitlabManager;
 
-    public readonly versionUpdateInformationPeriodHours: number;
+    public versionUpdateInformationPeriodHours!: number;
 
-    public readonly gitlab: {
+    public gitlab!: {
         cliReleasePage: string
         cliPreAlphaReleasePage: string
     };
 
-    public readonly login: {
+    public login!: {
         server: {
             port: number, route: string
         }, gitlab: {
@@ -23,51 +22,52 @@ class Config {
         }
     };
 
-    public readonly folders: {
+    public folders!: {
         defaultLocalExercise: string
     };
 
-    public readonly exercise: {
+    public exercise!: {
         neededFiles: Array<string>
     };
 
-    public interactiveMode: boolean;
+    public interactiveMode!: boolean;
 
-    constructor() {
-        this.localConfig = {
-            folder     : getAppDataPath('DojoCLI'),
-            sessionFile: process.env.LOCAL_CONFIG_FILE_SESSION || '',
-            stateFile  : process.env.LOCAL_CONFIG_STATE || ''
-        };
+    constructor() { }
+
+    async init(apiUrl: string) {
+        await ClientsSharedConfig.init(apiUrl);
+        const getEnvVar = ClientsSharedConfig.envVarGetter();
+
+        this.gitlabManager = new GitlabManager(ClientsSharedConfig.gitlab.URL, ClientsSharedConfig.login.gitlab.client.id, ClientsSharedConfig.login.gitlab.url.redirect, ClientsSharedConfig.login.gitlab.url.token);
 
-        this.versionUpdateInformationPeriodHours = Number(process.env.VERSION_UPDATE_INFORMATION_PERIOD_HOURS || 24);
+        this.versionUpdateInformationPeriodHours = Number(getEnvVar('VERSION_UPDATE_INFORMATION_PERIOD_HOURS', '24'));
 
         this.gitlab = {
-            cliReleasePage        : process.env.GITLAB_CLI_RELEASE_PAGE || '',
-            cliPreAlphaReleasePage: process.env.GITLAB_CLI_PREALPHA_RELEASE_PAGE || ''
+            cliReleasePage        : getEnvVar('GITLAB_CLI_RELEASE_PAGE', ''),
+            cliPreAlphaReleasePage: getEnvVar('GITLAB_CLI_PREALPHA_RELEASE_PAGE', '')
         };
 
         this.login = {
             server: {
-                port : Number(process.env.LOGIN_SERVER_PORT || 30992),
-                route: process.env.LOGIN_SERVER_ROUTE || ''
+                port : Number(getEnvVar('LOGIN_SERVER_PORT', '30992')),
+                route: getEnvVar('LOGIN_SERVER_ROUTE', '')
             },
             gitlab: {
                 url: {
-                    code: process.env.LOGIN_GITLAB_URL_CODE || ''
+                    code: getEnvVar('LOGIN_GITLAB_URL_CODE', '')
                 }
             }
         };
 
         this.folders = {
-            defaultLocalExercise: process.env.LOCAL_EXERCISE_DEFAULT_FOLDER || './'
+            defaultLocalExercise: getEnvVar('LOCAL_EXERCISE_DEFAULT_FOLDER', './')
         };
 
         this.exercise = {
-            neededFiles: JSON.parse(process.env.EXERCISE_NEEDED_FILES || '[]')
+            neededFiles: JSON.parse(getEnvVar('EXERCISE_NEEDED_FILES', '[]'))
         };
 
-        this.interactiveMode = process.env.INTERACTIVE_MODE === 'true';
+        this.interactiveMode = getEnvVar('INTERACTIVE_MODE', 'false') === 'true';
     }
 }
 
diff --git a/NodeApp/src/config/ConfigFiles.ts b/NodeApp/src/config/ConfigFiles.ts
index 9744e260e423d853a0fc25d81e106bb191e40a22..c92fb278f160ed71fb73c74b0f287e08a3ec2cce 100644
--- a/NodeApp/src/config/ConfigFiles.ts
+++ b/NodeApp/src/config/ConfigFiles.ts
@@ -1,9 +1,28 @@
 import LocalConfigFile from './LocalConfigFile.js';
-import Config          from './Config.js';
+import getAppDataPath  from 'appdata-path';
 
 
-const sessionConfigFile = new LocalConfigFile(Config.localConfig.sessionFile);
-const stateConfigFile = new LocalConfigFile(Config.localConfig.stateFile);
+class ConfigFiles {
+    private localConfig: {
+        folder: string; sessionFile: string; stateFile: string;
+    };
 
+    public sessionConfigFile!: LocalConfigFile;
+    public stateConfigFile!: LocalConfigFile;
 
-export { sessionConfigFile, stateConfigFile };
\ No newline at end of file
+    constructor() {
+        this.localConfig = {
+            folder     : getAppDataPath('DojoCLI'),
+            sessionFile: process.env.LOCAL_CONFIG_FILE_SESSION ?? '',
+            stateFile  : process.env.LOCAL_CONFIG_FILE_STATE ?? ''
+        };
+    }
+
+    init() {
+        this.sessionConfigFile = new LocalConfigFile(this.localConfig.folder, this.localConfig.sessionFile);
+        this.stateConfigFile = new LocalConfigFile(this.localConfig.folder, this.localConfig.stateFile);
+    }
+}
+
+
+export default new ConfigFiles();
\ No newline at end of file
diff --git a/NodeApp/src/config/LocalConfigFile.ts b/NodeApp/src/config/LocalConfigFile.ts
index 29f62a6343defe952125d6e52b546fbd7f5e7057..996e6e19483fc1aad19c8317440b701cfac14105 100644
--- a/NodeApp/src/config/LocalConfigFile.ts
+++ b/NodeApp/src/config/LocalConfigFile.ts
@@ -1,26 +1,27 @@
 import * as fs from 'fs';
-import Config  from './Config.js';
 import JSON5   from 'json5';
 
 
 class LocalConfigFile {
+    private readonly folder: string;
     private readonly filename: string;
 
-    constructor(filename: string) {
+    constructor(folder: string, filename: string) {
+        this.folder = folder;
         this.filename = filename;
 
         this.loadConfig();
     }
 
     private get configPath(): string {
-        return `${ Config.localConfig.folder }/${ this.filename }`;
+        return `${ this.folder }/${ this.filename }`;
     }
 
     private _config: { [key: string]: unknown } = {};
 
     loadConfig() {
         if ( !fs.existsSync(this.configPath) ) {
-            fs.mkdirSync(Config.localConfig.folder, { recursive: true });
+            fs.mkdirSync(this.folder, { recursive: true });
 
             fs.writeFileSync(this.configPath, JSON5.stringify({}));
         }
diff --git a/NodeApp/src/helpers/AccessesHelper.ts b/NodeApp/src/helpers/AccessesHelper.ts
index a07b7aa24a40229be5460f1126e0e99eb4455138..cc5f2a4e2a3a838f4d9af497f47df8012e6aea06 100644
--- a/NodeApp/src/helpers/AccessesHelper.ts
+++ b/NodeApp/src/helpers/AccessesHelper.ts
@@ -1,5 +1,5 @@
 import SessionManager from '../managers/SessionManager.js';
-import GitlabManager  from '../managers/GitlabManager.js';
+import Config         from '../config/Config';
 
 
 class AccessesHelper {
@@ -10,7 +10,7 @@ class AccessesHelper {
             throw new Error();
         }
 
-        if ( testGitlab && !(await GitlabManager.testToken(true)).every(result => result) ) {
+        if ( testGitlab && !(await Config.gitlabManager.testToken(true)).every(result => result) ) {
             throw new Error();
         }
     }
diff --git a/NodeApp/src/helpers/Dojo/ExerciseRunHelper.ts b/NodeApp/src/helpers/Dojo/ExerciseRunHelper.ts
index 235bc74664d12d874fe945f5582f652852c30568..0503c66adf4d4230ce8f2600d4e1512d96c3ef18 100644
--- a/NodeApp/src/helpers/Dojo/ExerciseRunHelper.ts
+++ b/NodeApp/src/helpers/Dojo/ExerciseRunHelper.ts
@@ -5,7 +5,6 @@ import AssignmentFile                       from '../../shared/types/Dojo/Assign
 import ExerciseDockerCompose                from '../../sharedByClients/helpers/Dojo/ExerciseDockerCompose.js';
 import ExerciseResultsSanitizerAndValidator from '../../sharedByClients/helpers/Dojo/ExerciseResultsSanitizerAndValidator.js';
 import fs                                   from 'node:fs';
-import ClientsSharedConfig                  from '../../sharedByClients/config/ClientsSharedConfig.js';
 import SharedAssignmentHelper               from '../../shared/helpers/Dojo/SharedAssignmentHelper.js';
 import path                                 from 'path';
 import ExerciseCheckerError                 from '../../shared/types/Dojo/ExerciseCheckerError.js';
@@ -15,6 +14,7 @@ import util                                 from 'util';
 import { exec }                             from 'child_process';
 import SharedConfig                         from '../../shared/config/SharedConfig.js';
 import TextStyle                            from '../../types/TextStyle.js';
+import ClientsSharedConfig                  from '../../sharedByClients/config/ClientsSharedConfig';
 
 
 const execAsync = util.promisify(exec);
diff --git a/NodeApp/src/helpers/GlobalHelper.ts b/NodeApp/src/helpers/GlobalHelper.ts
index d79317fd487a954157d4287071daaf8b345f578a..dc9d2442afe43d4e9b16d077fa3c0dd17ad3abf5 100644
--- a/NodeApp/src/helpers/GlobalHelper.ts
+++ b/NodeApp/src/helpers/GlobalHelper.ts
@@ -1,10 +1,10 @@
 import { Command, Option } from 'commander';
-import Config              from '../config/Config.js';
 import SessionManager      from '../managers/SessionManager.js';
 import TextStyle           from '../types/TextStyle.js';
 import ora                 from 'ora';
 import DojoBackendManager  from '../managers/DojoBackendManager.js';
 import Assignment          from '../sharedByClients/models/Assignment.js';
+import Config              from '../config/Config';
 
 
 class GlobalHelper {
diff --git a/NodeApp/src/managers/DojoBackendManager.ts b/NodeApp/src/managers/DojoBackendManager.ts
index 0a878367581dbd7022567590557cf88222c05d00..50c2c0e01201345dd26e8f7d5375e24b20d0c881 100644
--- a/NodeApp/src/managers/DojoBackendManager.ts
+++ b/NodeApp/src/managers/DojoBackendManager.ts
@@ -1,7 +1,6 @@
 import axios, { AxiosError } from 'axios';
 import ora                   from 'ora';
 import ApiRoute              from '../sharedByClients/types/Dojo/ApiRoute.js';
-import ClientsSharedConfig   from '../sharedByClients/config/ClientsSharedConfig.js';
 import Assignment            from '../sharedByClients/models/Assignment.js';
 import DojoBackendResponse   from '../shared/types/Dojo/DojoBackendResponse.js';
 import Exercise              from '../sharedByClients/models/Exercise.js';
@@ -14,10 +13,121 @@ import GitlabPipelineStatus  from '../shared/types/Gitlab/GitlabPipelineStatus.j
 import Tag                   from '../sharedByClients/models/Tag';
 import TagProposal           from '../sharedByClients/models/TagProposal';
 import Result                from '../sharedByClients/models/Result';
+import ClientsSharedConfig   from '../sharedByClients/config/ClientsSharedConfig';
+import inquirer              from 'inquirer';
+import SharedConfig          from '../shared/config/SharedConfig';
+import ConfigFiles           from '../config/ConfigFiles';
 
 
 class DojoBackendManager {
-    private handleApiError(error: unknown, spinner: ora.Ora, verbose: boolean, defaultErrorMessage?: string, otherErrorHandler?: (error: AxiosError, spinner: ora.Ora, verbose: boolean) => void) {
+    readonly API_URL_CONFIG_KEY = 'apiUrl';
+
+    public async getApiUrl(): Promise<string> {
+        //Read the config file to get the api url. If there is no api url, then ask the user to provide one.
+        return ConfigFiles.stateConfigFile.getParam(this.API_URL_CONFIG_KEY) as string | null || await this.askApiUrl();
+    }
+
+    public async cleanApiUrl(): Promise<void> {
+        const cleanApiSpinner: ora.Ora = ora('Cleaning Api URL...').start();
+        ConfigFiles.stateConfigFile.setParam(this.API_URL_CONFIG_KEY, null);
+        cleanApiSpinner.succeed('API URL successfully cleaned');
+    }
+
+    /**
+     * Check if the given api url is valid and save it in the config file if it is.
+     * @param apiUrl
+     * @returns {Promise<boolean>} true if the api url is valid, false otherwise
+     */
+    public async setApiUrl(apiUrl: string): Promise<boolean> {
+        let isApiUrlValid: boolean = false;
+
+        const testApiSpinner: ora.Ora = ora('Testing Api URL...').start();
+        try {
+            isApiUrlValid = (await axios.get<DojoBackendResponse<unknown>>(`${ apiUrl }${ ApiRoute.CLIENTS_CONFIG }`)).status === 200;
+        } catch ( e ) {
+            isApiUrlValid = false;
+        }
+
+        if ( isApiUrlValid ) {
+            // End step: Store the preference in the config file
+            ConfigFiles.stateConfigFile.setParam(this.API_URL_CONFIG_KEY, apiUrl);
+        }
+
+        isApiUrlValid ? testApiSpinner.succeed('API URL successfully saved') : testApiSpinner.fail('The API URL is invalid');
+
+        return isApiUrlValid;
+    }
+
+    public async askApiUrl(showClean: boolean = false): Promise<string> {
+        const presets: Array<{ name: string, value: string } | inquirer.Separator> = [ {
+            name : 'HEPIA',
+            value: 'https://rdps.hesge.ch/dojo/api'
+        }, {
+            name : 'Other',
+            value: 'other'
+        } ];
+
+        if ( !SharedConfig.production ) {
+            presets.unshift({
+                                name : 'DEV',
+                                value: 'http://localhost:30993'
+                            }, {
+                                name : 'TEST',
+                                value: 'https://dojo-test.edu.hesge.ch/dojo/api'
+                            }, new inquirer.Separator());
+        }
+
+        if ( showClean ) {
+            presets.push(new inquirer.Separator(), {
+                name : 'Clean API settings',
+                value: 'clean'
+            });
+        }
+
+        presets.push(new inquirer.Separator(), {
+            name : 'Quit',
+            value: 'quit'
+        });
+
+        let apiUrl: string = '';
+        let isApiUrlValid: boolean = false;
+
+        do {
+            // First step: Propose some presets with inquirer
+            apiUrl = (await inquirer.prompt({
+                                                name    : 'apiUrl',
+                                                message : 'Which API do you want to use?',
+                                                type    : 'list',
+                                                pageSize: 1000,
+                                                choices : presets,
+                                                default : SharedConfig.production ? 'other' : 'http://localhost:30993'
+                                            })).apiUrl;
+
+
+            // Second step: If the user chooses other, then ask for the url of the api
+            switch ( apiUrl ) {
+                case 'other':
+                    apiUrl = (await inquirer.prompt({
+                                                        name   : 'apiUrl',
+                                                        message: 'Please provide the URL of the API',
+                                                        type   : 'input'
+                                                    })).apiUrl;
+                    break;
+                case 'clean':
+                    await this.cleanApiUrl();
+                    return '';
+                case 'quit':
+                    process.exit(0);
+            }
+
+            // Third step: Test the api url
+            isApiUrlValid = await this.setApiUrl(apiUrl);
+        } while ( !isApiUrlValid );
+
+        return apiUrl;
+    }
+
+    private async handleApiError(error: unknown, spinner: ora.Ora, verbose: boolean, defaultErrorMessage?: string, otherErrorHandler?: (error: AxiosError, spinner: ora.Ora, verbose: boolean) => void) {
         const unknownErrorMessage: string = 'unknown error';
 
         if ( verbose ) {
@@ -129,7 +239,7 @@ class DojoBackendManager {
 
             return true;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Template error: ${ error }`);
+            await this.handleApiError(error, spinner, verbose, `Template error: ${ error }`);
 
             return false;
         }
@@ -154,7 +264,7 @@ class DojoBackendManager {
 
             return response.data.data;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Assignment creation error: unknown error`);
+            await this.handleApiError(error, spinner, verbose, `Assignment creation error: unknown error`);
 
             throw error;
         }
@@ -176,7 +286,7 @@ class DojoBackendManager {
 
             return response.data.data;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Exercise creation error: unknown error`);
+            await this.handleApiError(error, spinner, verbose, `Exercise creation error: unknown error`);
 
             throw error;
         }
@@ -198,7 +308,7 @@ class DojoBackendManager {
 
             return;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Assignment visibility change error: ${ error }`);
+            await this.handleApiError(error, spinner, verbose, `Assignment visibility change error: ${ error }`);
 
             throw error;
         }
@@ -230,7 +340,7 @@ class DojoBackendManager {
 
             return true;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Correction ${ isUpdate ? 'update' : 'link' } error: ${ error }`);
+            await this.handleApiError(error, spinner, verbose, `Correction ${ isUpdate ? 'update' : 'link' } error: ${ error }`);
 
             return false;
         }
@@ -255,7 +365,7 @@ class DojoBackendManager {
 
             return true;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Correction unlink error: ${ error }`);
+            await this.handleApiError(error, spinner, verbose, `Correction unlink error: ${ error }`);
 
             return false;
         }
@@ -280,7 +390,7 @@ class DojoBackendManager {
 
             return response.data.data;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Tag creation error: ${ error }`);
+            await this.handleApiError(error, spinner, verbose, `Tag creation error: ${ error }`);
 
             return undefined;
         }
@@ -302,7 +412,7 @@ class DojoBackendManager {
 
             return true;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Tag deletion error: ${ error }`);
+            await this.handleApiError(error, spinner, verbose, `Tag deletion error: ${ error }`);
 
             return false;
         }
@@ -335,7 +445,7 @@ class DojoBackendManager {
 
             return response.data.data;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Tag proposal creation error: ${ error }`);
+            await this.handleApiError(error, spinner, verbose, `Tag proposal creation error: ${ error }`);
 
             return undefined;
         }
@@ -360,7 +470,7 @@ class DojoBackendManager {
 
             return true;
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Tag proposal answer error: ${ error }`);
+            await this.handleApiError(error, spinner, verbose, `Tag proposal answer error: ${ error }`);
 
             return false;
         }
@@ -405,7 +515,7 @@ class DojoBackendManager {
                 spinner.succeed(`Exercise deleted with success`);
             }
         } catch ( error ) {
-            this.handleApiError(error, spinner, verbose, `Exercise deleting error: ${ error }`);
+            await this.handleApiError(error, spinner, verbose, `Exercise deleting error: ${ error }`);
 
             throw error;
         }
diff --git a/NodeApp/src/managers/GitlabManager.ts b/NodeApp/src/managers/GitlabManager.ts
index 0e6c92e364f91e6cfe1be20508acd20dd2aee73b..a39a26e477e2f2c532411344fdbf11ac7e11ff2f 100644
--- a/NodeApp/src/managers/GitlabManager.ts
+++ b/NodeApp/src/managers/GitlabManager.ts
@@ -11,8 +11,8 @@ type getGitlabUser = (param: number | string) => Promise<UserSchema | undefined>
 
 
 class GitlabManager extends SharedGitlabManager {
-    constructor() {
-        super('', GlobalHelper.refreshGitlabTokenFunction.bind(GlobalHelper));
+    constructor(public gitlabUrl: string, clientId?: string, urlRedirect?: string, urlToken?: string) {
+        super(gitlabUrl, '', clientId, urlRedirect, urlToken, GlobalHelper.refreshGitlabTokenFunction.bind(GlobalHelper));
     }
 
     public async testToken(verbose: boolean = true): Promise<[ boolean, boolean ]> {
@@ -213,4 +213,4 @@ class GitlabManager extends SharedGitlabManager {
 }
 
 
-export default new GitlabManager();
+export default GitlabManager;
diff --git a/NodeApp/src/managers/HttpManager.ts b/NodeApp/src/managers/HttpManager.ts
index 760f19c1f1f0b4d12089bd6f9badd84e68eb424d..ce1bc53e8c7a792b9c1c5c179fe894eecb0af788 100644
--- a/NodeApp/src/managers/HttpManager.ts
+++ b/NodeApp/src/managers/HttpManager.ts
@@ -2,13 +2,13 @@ import axios, { AxiosError, AxiosRequestHeaders } from 'axios';
 import SessionManager                             from './SessionManager.js';
 import FormData                                   from 'form-data';
 import { StatusCodes }                            from 'http-status-codes';
-import ClientsSharedConfig                        from '../sharedByClients/config/ClientsSharedConfig.js';
 import { version }                                from '../config/Version.js';
 import DojoBackendResponse                        from '../shared/types/Dojo/DojoBackendResponse.js';
 import DojoStatusCode                             from '../shared/types/Dojo/DojoStatusCode.js';
 import boxen                                      from 'boxen';
-import { stateConfigFile }                        from '../config/ConfigFiles.js';
 import TextStyle                                  from '../types/TextStyle.js';
+import ConfigFiles                                from '../config/ConfigFiles';
+import ClientsSharedConfig                        from '../sharedByClients/config/ClientsSharedConfig';
 
 
 class HttpManager {
@@ -25,9 +25,7 @@ class HttpManager {
                 config.headers = { ...config.headers, ...config.data.getHeaders() } as AxiosRequestHeaders;
             }
 
-            if ( config.url && (config.url.indexOf(ClientsSharedConfig.apiURL) !== -1) ) {
-
-
+            if ( config.url && config.url.indexOf(ClientsSharedConfig.apiURL) !== -1 ) {
                 config.headers['Accept-Encoding'] = 'gzip';
 
                 if ( config.data && Object.keys(config.data as { [key: string]: unknown }).length > 0 ) {
@@ -106,11 +104,11 @@ class HttpManager {
 
             if ( response.headers['dojocli-latest-version'] ) {
                 const latestDojoCliVersion = response.headers['dojocli-latest-version'];
-                const storedLatestDojoCliVersion = stateConfigFile.getParam('latestDojoCliVersion') as string | null || '0.0.0';
+                const storedLatestDojoCliVersion = ConfigFiles.stateConfigFile.getParam('latestDojoCliVersion') as string | null || '0.0.0';
 
                 if ( latestDojoCliVersion !== storedLatestDojoCliVersion ) {
-                    stateConfigFile.setParam('latestDojoCliVersion', latestDojoCliVersion);
-                    stateConfigFile.setParam('latestDojoCliVersionNotification', 0);
+                    ConfigFiles.stateConfigFile.setParam('latestDojoCliVersion', latestDojoCliVersion);
+                    ConfigFiles.stateConfigFile.setParam('latestDojoCliVersionNotification', 0);
                 }
             }
 
diff --git a/NodeApp/src/managers/SessionManager.ts b/NodeApp/src/managers/SessionManager.ts
index 7dd62ccf351bf0cf66acc08f17f907c7a6adfcfb..cffc6b979e3f1aa2e43f64a2944334461ea83865 100644
--- a/NodeApp/src/managers/SessionManager.ts
+++ b/NodeApp/src/managers/SessionManager.ts
@@ -7,21 +7,19 @@ import ora                   from 'ora';
 import Permissions           from '../types/Permissions.js';
 import ApiRoute              from '../sharedByClients/types/Dojo/ApiRoute.js';
 import DojoBackendManager    from './DojoBackendManager.js';
-import Config                from '../config/Config.js';
-import ClientsSharedConfig   from '../sharedByClients/config/ClientsSharedConfig.js';
 import DojoGitlabCredentials from '../sharedByClients/types/Dojo/DojoGitlabCredentials.js';
 import * as http             from 'http';
 import EventEmitter          from 'events';
-import SharedConfig          from '../shared/config/SharedConfig.js';
 import chalk                 from 'chalk';
 import inquirer              from 'inquirer';
 import GitlabToken           from '../shared/types/Gitlab/GitlabToken.js';
 import open                  from 'open';
-import { sessionConfigFile } from '../config/ConfigFiles.js';
 import TextStyle             from '../types/TextStyle.js';
 import DojoBackendHelper     from '../sharedByClients/helpers/Dojo/DojoBackendHelper.js';
-import GitlabManager         from './GitlabManager.js';
 import { StatusCodes }       from 'http-status-codes';
+import ConfigFiles           from '../config/ConfigFiles';
+import Config                from '../config/Config';
+import ClientsSharedConfig   from '../sharedByClients/config/ClientsSharedConfig';
 
 
 class LoginServer {
@@ -82,7 +80,7 @@ class SessionManager {
     }
 
     get apiToken(): string {
-        const apisToken = sessionConfigFile.getParam(LocalConfigKeys.APIS_TOKEN) as null | { [key: string]: string };
+        const apisToken = ConfigFiles.sessionConfigFile.getParam(LocalConfigKeys.APIS_TOKEN) as null | { [key: string]: string };
 
         if ( apisToken !== null && ClientsSharedConfig.apiURL in apisToken ) {
             return apisToken[ClientsSharedConfig.apiURL];
@@ -92,12 +90,12 @@ class SessionManager {
     }
 
     set apiToken(token: string) {
-        let apisToken = sessionConfigFile.getParam(LocalConfigKeys.APIS_TOKEN) as null | { [key: string]: string };
+        let apisToken = ConfigFiles.sessionConfigFile.getParam(LocalConfigKeys.APIS_TOKEN) as null | { [key: string]: string };
         if ( apisToken === null ) {
             apisToken = {};
         }
         apisToken[ClientsSharedConfig.apiURL] = token;
-        sessionConfigFile.setParam(LocalConfigKeys.APIS_TOKEN, apisToken);
+        ConfigFiles.sessionConfigFile.setParam(LocalConfigKeys.APIS_TOKEN, apisToken);
 
         try {
             const payload = jwt.decode(token);
@@ -111,14 +109,14 @@ class SessionManager {
     }
 
     get gitlabCredentials(): DojoGitlabCredentials {
-        return sessionConfigFile.getParam(LocalConfigKeys.GITLAB) as DojoGitlabCredentials;
+        return ConfigFiles.sessionConfigFile.getParam(LocalConfigKeys.GITLAB) as DojoGitlabCredentials;
     }
 
     set gitlabCredentials(credentials: DojoGitlabCredentials) {
-        sessionConfigFile.setParam(LocalConfigKeys.GITLAB, credentials);
+        ConfigFiles.sessionConfigFile.setParam(LocalConfigKeys.GITLAB, credentials);
 
         if ( credentials.accessToken ) {
-            GitlabManager.setToken(credentials.accessToken);
+            Config.gitlabManager.setToken(credentials.accessToken);
         }
     }
 
@@ -127,7 +125,7 @@ class SessionManager {
         console.log(`${ indent }Please open the following URL in your web browser and accept to give the requested permissions to Dojo:`);
         console.log(TextStyle.URL(`${ indent }${ Config.login.gitlab.url.code }`));
         console.log(`${ indent }Then, copy the code at the end of the redirected url and paste it bellow.`);
-        console.log(`${ indent }Example of url (here the code is 123456): ${ TextStyle.URL(SharedConfig.login.gitlab.url.redirect + '?code=') }${ chalk.green('123456') }`);
+        console.log(`${ indent }Example of url (here the code is 123456): ${ TextStyle.URL(ClientsSharedConfig.login.gitlab.url.redirect + '?code=') }${ chalk.green('123456') }`);
         return (await inquirer.prompt({
                                           type   : 'password',
                                           name   : 'code',
@@ -194,7 +192,7 @@ class SessionManager {
             throw error;
         }
 
-        ora(`Login with Gitlab (${ SharedConfig.gitlab.URL }):`).start().info();
+        ora(`Login with Gitlab (${ ClientsSharedConfig.gitlab.URL }):`).start().info();
 
         let gitlabCode: string;
         if ( !headless ) {
@@ -209,7 +207,7 @@ class SessionManager {
                                         }).start();
         let gitlabTokens: GitlabToken;
         try {
-            gitlabTokens = await GitlabManager.getTokens(gitlabCode);
+            gitlabTokens = await Config.gitlabManager.getTokens(gitlabCode);
             this.gitlabCredentials = {
                 refreshToken: gitlabTokens.refresh_token,
                 accessToken : gitlabTokens.access_token
@@ -220,7 +218,7 @@ class SessionManager {
             throw error;
         }
 
-        const isGitlabTokensValid = (await GitlabManager.testToken()).every(value => value);
+        const isGitlabTokensValid = (await Config.gitlabManager.testToken()).every(value => value);
         if ( !isGitlabTokensValid ) {
             throw new Error('Gitlab tokens are invalid');
         }
diff --git a/NodeApp/src/shared b/NodeApp/src/shared
index bf75a99ba472386daa111c2fefbe69a4272ef48c..d9ecaee5f58b1b94413903ebf737b4d235bc2858 160000
--- a/NodeApp/src/shared
+++ b/NodeApp/src/shared
@@ -1 +1 @@
-Subproject commit bf75a99ba472386daa111c2fefbe69a4272ef48c
+Subproject commit d9ecaee5f58b1b94413903ebf737b4d235bc2858
diff --git a/NodeApp/src/sharedByClients b/NodeApp/src/sharedByClients
index 4e33e70f6035898f119369ae5db784d51d8298a0..64dc406659114f3afcbc89258afe84c8553c6b8f 160000
--- a/NodeApp/src/sharedByClients
+++ b/NodeApp/src/sharedByClients
@@ -1 +1 @@
-Subproject commit 4e33e70f6035898f119369ae5db784d51d8298a0
+Subproject commit 64dc406659114f3afcbc89258afe84c8553c6b8f