Neue Rituale Posted June 20, 2023 Posted June 20, 2023 Thanks for the great modules. Maybe this was answered, unfortunately I didn't find anything about it. How can I remove or overwrite the routes from "DefaultRoutes.php"? I have already tried it with this: $module = $this->wire('modules')->get('AppAPI'); $module->registerRoute( 'auth', [ ['OPTIONS', '', AppApiHelper::class, 'noEndPoint'], ['GET', '', AppApiHelper::class, 'noEndPoint'], ['POST', '', AppApiHelper::class, 'noEndPoint'], ['DELETE', '', AppApiHelper::class, 'noEndPoint'], ] ); Unfortunately, they are still accessible and functional.
zoeck Posted June 21, 2023 Posted June 21, 2023 On 6/18/2023 at 1:46 AM, Sebi said: The overview page has a button to auto-generate an OpenAPI 3.0.3 json, that can be imported in tools like Postman or Swagger. I have one more small suggestion to improve the function a bit ? Just replace the complete if inside the execute-endpoints.php file: if ($action === 'action-get-openapi') { [...] } With this: if ($action === 'action-get-openapi') { header('Content-Type: application/json; charset=utf-8'); echo json_encode($openApiOutput, JSON_PRETTY_PRINT + JSON_UNESCAPED_SLASHES + JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_LINE_TERMINATORS); die(); } So Tracy is disabled on output and via the browser you can save the file directly as json. And Thanks for this nice update ? @Sebi 1 1
eelkenet Posted September 7, 2023 Posted September 7, 2023 Hi @Sebi, I'm about to start work on a web-app that will (hopefully) use AppApi with 2-factor authentication, using the TOTP module from Ryan. I would like to use the Double JWT authentication for the most secure set-up. As I understand, this would currently not be possible, except maybe if I resort to PHP session instead and create my own login endpoint that implements some of the TfaTotp module methods. Is that correct? Or do you have any pointers as to how to implement this with Double JWT?
rastographics Posted September 13, 2023 Posted September 13, 2023 For Double JWT approach, have you considered sending tokens to client using httpOnly cookie? I'm not an expert on this topic, but when researching to see where to save the tokens in my app, it seems the opinion for most secure involves httpOnly cookie (among other things). One such conversation:https://stackoverflow.com/questions/27067251/where-to-store-jwt-in-browser-how-to-protect-against-csrf?rq=1 Do you currently use localstorage on the browser? I'm creating a new app. Your module is awesome. But I'm wondering if localstorage is most secure on client? And how to do httpOnly cookie with this module?
gerritvanaaken Posted September 25, 2023 Posted September 25, 2023 This may be a silly question, but I couldn’t access the payload/body of a POST request within the public static function. The $data variable only contains the path, but not the body of the request. My code goes like this: 'email' => [ ['OPTIONS', '', ['POST']], ['POST', '', Email::class, 'sendEmail'] ], class Email { public static function sendEmail ($data) { var_dump($data); // contains only path var_dump(wire('input')); // "post" data is null My goal here is, of course, to send an email from a JavaScript application, using my PW installation as proxy.
gerritvanaaken Posted September 25, 2023 Posted September 25, 2023 Nevermind. My POST request had the wrong Content Type Header.
eelkenet Posted October 6, 2023 Posted October 6, 2023 On 9/7/2023 at 12:25 PM, eelkenet said: Hi @Sebi, I'm about to start work on a web-app that will (hopefully) use AppApi with 2-factor authentication, using the TOTP module from Ryan. I would like to use the Double JWT authentication for the most secure set-up. I have moved away from the Double JWT solution for now, as PHP sessions seem to work fine for my application. Also I managed to implement TFA validation, by editing the `classes/Auth.php` file. That seemed to be the only way I could do so: I tried hooking into ___doLogin() but couldnt figure out the order of things. See below! So, I replaced line 164: $loggedIn = $this->wire('session')->login($user->name, $password); With // Add Tfa authentication through TfaTotp if ($user->hasTfa()) { $tfa = $user->hasTfa(true); // Get code from incoming data // This only works if credentials + 2FA get sent inside the body $code = null; if ( isset($data->tfacode) && !empty('' . $data->tfacode) ) { $code = $data->tfacode; } $settings = $tfa->getUserSettings($user); if ($code && $tfa->isValidUserCode($user, $code, $settings)) { $loggedIn = $this->wire('session')->login($user->name, $password); } else { throw new AuthException("Invalid TFA code", 401); } } else { $loggedIn = $this->wire('session')->login($user->name, $password); } And then added the 2FA in the body request: // inside a log-in method const credentials = { email: this.identification, password: this.password, tfacode: this.tfacode, }; const response = await fetch('/api/auth', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'MY_API_KEY', }, body: JSON.stringify(credentials), }); if (response.ok) { return response.json(); } else { let error = await response.json(); throw new Error(JSON.stringify(error)); } I have also managed to do a proof of concept of a register route that works in combination with the TfaTotp module, but that needs some polishing. Update: I figured out that, in order to get be able to hook into Auth::doLogin, I needed to check the 'Deactivate URL Hook' toggle in the AppApi module settings. After doing so, I can now successfully hook and check for the Tfa, hurrah! // In ready.php wire()->addHookAfter('Auth::doLogin', function (HookEvent $event) { $log = wire('log'); $session = wire('session'); // Get the original return value of ___doLogin $originalReturnValue = $event->return; // Check if the original login was successful if (isset($originalReturnValue['username']) && !empty($originalReturnValue['username'])) { $username = $originalReturnValue['username']; $user = $event->wire('users')->get("name=$username"); // Check if the user has TFA activated if ($user->hasTfa()) { $tfa = $user->hasTfa(true); // Get code from incoming data // This only works if 2FA gets sent inside the body, along with password and username $data = $event->arguments(0); $code = null; if (isset($data->tfacode) && !empty('' . $data->tfacode)) { $code = $data->tfacode; } $settings = $tfa->getUserSettings($user); if ($code && $tfa->isValidUserCode($user, $code, $settings)) { $log->save("tfaLogin", "Tfa code = correct!"); $event->return = $originalReturnValue; } // Incorrect Tfa, sign out and throw 401 else { $log->save("tfaLogin", "Tfa code = incorrect, do not allow logging in"); $session->logout(); throw new AuthException("Code incorrect!", 401); } } // No Tfa enabled, sign out and throw 401 else { $log->save("tfaLogin", "User does not have Tfa enabled.. do not allow logging in!"); $session->logout(); throw new AuthException("TFA not enabled!", 401); } } });
rastographics Posted October 23, 2023 Posted October 23, 2023 @Sebiwould you be open to a pull request that adds a new setting? Access Token Expires In? I see that the access token uses the $config->sessionExpireInSeconds value for the access token expiration. However, using JWT, I would like to have a shorter (60 minutes) session, because of using the Refresh Token to keep things logged in. For the rest of my site (not using AppApi), the normal users I want to have 24 hour session, which I set with $config->sessionExpireInSeconds. There is already an Expires At setting in AppApi, for Refresh Token. Is it okay to add a second Expires At setting for Access Token, in case we want to set a different expiration from rest of site? Hope this makes sense?
rastographics Posted October 23, 2023 Posted October 23, 2023 31 minutes ago, rastographics said: @Sebiwould you be open to a pull request that adds a new setting? Access Token Expires In? I see that the access token uses the $config->sessionExpireInSeconds value for the access token expiration. However, using JWT, I would like to have a shorter (60 minutes) session, because of using the Refresh Token to keep things logged in. For the rest of my site (not using AppApi), the normal users I want to have 24 hour session, which I set with $config->sessionExpireInSeconds. There is already an Expires At setting in AppApi, for Refresh Token. Is it okay to add a second Expires At setting for Access Token, in case we want to set a different expiration from rest of site? Hope this makes sense? For now I'm doing this on line 271 of AppApi/classes/Auth.php . But I have to be careful when updating the module now. /* ADDED TO GIVE JWT ACCESS TOKEN A DIFFERENT SESSION LENGTH THAN REGULAR SITE LOGINS */ $config = $this->wire('config'); $expireSeconds = $config->sessionExpireSeconds; if(isset($config->appApiSessionExpireSeconds)){ $expireSeconds = $config->appApiSessionExpireSeconds; } $apptoken->setExpirationTime(time() + $expireSeconds);
gerritvanaaken Posted March 13, 2024 Posted March 13, 2024 Hallo, I have some problems with special characters in POST URLs. It’s awkward. These are my routes: ['OPTIONS', 'tasks/{city}/{employee}', ['GET']], ['GET', 'tasks/{city}/{employee}', Googledocs::class, 'fetchTasks'], ['OPTIONS', 'tasks/{city}/{employee}/{row}', ['POST']], ['POST', 'tasks/{city}/{employee}/{row}', Googledocs::class, 'putTasksRow'] Employees with an Umlaut, however, seem to confuse the path/method detection: GET https://myapi.com/api/docs/tasks/wuerzburg/Pia-Mäder (works) POST https://myapi.com/api/docs/tasks/wuerzburg/Pia-Mäder (works, but shouldn’t) POST https://myapi.com/api/docs/tasks/wuerzburg/Pia-Mader (error 405, as intended) POST https://myapi.com/api/docs/tasks/wuerzburg/Pia-Mäder/42 (error 405, but should work) POST https://myapi.com/api/docs/tasks/wuerzburg/Pia-Mader/42 (works) (Yes, I should be using PUT or PATCH instead of POST, but my hosting provider has – strangely enough – a problem with Umlauts as well, when they are in PUT requests. It doesn’t even start PHP in these cases and throws an 405 error from Apache)
Jonathan Lahijani Posted April 26, 2024 Posted April 26, 2024 @Sebi Right now, it is possible to view the OpenAPI json by going to /admin/setup/appapi/endpoints/action-get-openapi/ I want to automate building html-based documentation with Redocly CLI based on that JSON data, however because how it is currently programmed, I can't use a script to cleanly grab that JSON nor is there a method that easily gets it in that format given how the code is structured (using the executeEndpoints method doesn't get the JSON in the same way and it relies on urlSegments). Is it possible to refactor the code / create a new method that would allow getting the OpenAPI JSON directly?
saerus Posted May 2 Posted May 2 Hi everyone, hi @sebi, First, thanks for this module I'm discovering at this moment 🙂 I got stuck a bit with something, so I wanted to share, in case. I installed my processwire in a subfolder, as I usually do. But with your module, i got 404 with all my fetches. So i tried to modify some stuff with the .htaccess, but never managed (point 8.A). Finally, I found out that in your "router.php", you have a "getCurrentUrl()" function that is using "$_SERVER['REQUEST_URI']". Unfortunately, when using a pw in a subfolder, this "$_SERVER['REQUEST_URI']" contains the full path. So the module would never find any route. // line 177 in "Router.php" $routeInfo = $dispatcher->dispatch($httpMethod, SELF::getCurrentUrl()); // with pw installed in a subfolder, this $routeInfo return an empty array Only way I found out is to modify this $ with a hook: $wire->addHookBefore('AppApi::handleApiRequest', function (HookEvent $event) { $scriptName = $_SERVER['SCRIPT_NAME']; $scriptDir = rtrim(dirname($scriptName), '/'); // print_r( $scriptDir."*"); $uri = $_SERVER['REQUEST_URI']; if (strpos($uri, $scriptDir) === 0) { $_SERVER['REQUEST_URI'] = substr($uri, strlen($scriptDir)); } }); Maybe there is another $ you could use there ? Or maybe I missed something. Anyway, like this, my fetches finally work, and I can really start to play with all of it 🙂 Thanks again ++
Jonathan Lahijani Posted May 21 Posted May 21 @Sebi Is there a reason there is not a simple "API-key based authentication" auth-type, meaning to communicate with the API, you just need an API key (without having to deal with sessions or JWTs)? Would you allow a pull request to add this? 1
markus-th Posted May 24 Posted May 24 On 5/21/2025 at 6:21 PM, Jonathan Lahijani said: @Sebi Is there a reason there is not a simple "API-key based authentication" auth-type, meaning to communicate with the API, you just need an API key (without having to deal with sessions or JWTs)? I only use the API key in Curl requests and that works perfectly. (PHP-Session) $url = "API-URL"; $curl = curl_init(); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_HTTPHEADER, array('x-api-key: *******************')); $data = curl_exec($curl); 1
Jonathan Lahijani Posted May 24 Posted May 24 7 hours ago, markus-th said: I only use the API key in Curl requests and that works perfectly. (PHP-Session) Ack! You're right. I did this API integration a year ago and I forgot about the 'auth' setting in my routes file. Thanks for mentioning this.
Jonathan Lahijani Posted June 7 Posted June 7 Just wanted to say this module is working really well under a lot of load. 👍 2
BlackDragon Posted September 17 Posted September 17 On 5/16/2021 at 6:09 PM, Sebi said: @thomasaullThank you! You are right - AppApiModule->checkIfApiRequest() compares with the full path of $_SERVER['REQUEST_URI']. Because of that, we must give the full path to the module-config, even if the ProcessWire root is in a subfolder. @Bacos: If you have only api instead of testeapi/api in your configuration, that would result in an 404 error! Hi, I've noticed that the base url in the OpenApi document is wrong with this configuration, e.g. "<domain>/testeapi/testeapi/api" instead of "<domain>/testeapi/api"
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now