We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 36470
    • 12 Posts
    Is it possible to authenticate an modx revolution user in an android app. Basically the app pulls content from restricted to member users resources.
      • 5430
      • 247 Posts
      You can do something very similar by setting up an endpoint on your modx site that accepts data requests from your app and the endpoint could pretty easily check a user's name/password credentials to verify they're authentic before responding with data. Because you can output pretty much anything via chunks/templates, it wouldn't be difficult to create JSON responses for valid requests. More details needed for a more specific reply.
        • 3749
        • 24,544 Posts
        It's not too difficult create a processor that will authenticate a MODX user, the trick is getting your App to make an Ajax call to the processor. The method depends on what language your app is written in.

        There's some useful information here.
          Did I help you? Buy me a beer
          Get my Book: MODX:The Official Guide
          MODX info for everyone: http://bobsguides.com/modx.html
          My MODX Extras
          Bob's Guides is now hosted at A2 MODX Hosting
          • 36470
          • 12 Posts
          Yes, you are right. I'll try to be more specific.

          Actually the app is not a native app, but an Ionic hybrid app. Ionic is built on angular js, so I am using this javascript code in the angular login controller:
          $http({
                  method: 'POST',
                  url: 'http://domain.dev/login.html',
                  headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                  transformRequest: function(obj) {
                      var str = [];
                      for(var p in obj)
                      str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                      return str.join("&");
                  },
                  data: $scope.loginData
              }).success(function () {
              });
          


          The code is doing nothing more then POSTing to "http://domain.dev/login.html" the username and the password (stored in $scop.loginData variable).
          The equivalent in JQuery would be something like this:
          $.post( "http://domain.dev/login.html", { username: "John", password: "123" });
          


          In the "login.html" resource (which uses blank template) I have this snippet:

          <?php
          if(isset($_POST) && count($_POST)){
              $c = array(
                  'username' => $_POST['username'],
                  'password' => $_POST['password']
              );
              $response = $modx->runProcessor('security/login',$c);
              if($response->response['success'] == 1){
                  $user['id'] = $modx->user->get('id');
                          $profile = $modx->user->getOne('Profile');
                  $user['fullname'] = $profile->get('fullname');
                  $user['email'] = $profile->get('email');
                  echo json_encode($user);
              }else{
                  echo json_encode($response->response); 
              }
          }
          


          Cross-site HTTP requests are allowed through the .htaccess file (the app obviously is not on the same domain as the modx installation smiley ):
          RewriteEngine On
          RewriteBase /
          RewriteCond %{REQUEST_FILENAME} !-d
          RewriteCond %{REQUEST_FILENAME} !-s
          RewriteRule ^(.*)$ index.php?_rest=$1 [QSA,NC,L]
          RewriteCond %{REQUEST_FILENAME} -d
          RewriteRule ^(.*)$ index.php [QSA,NC,L]
          
          # with AJAX withCredentials=false (cookies NOT sent)
          Header always set Access-Control-Allow-Origin "*"                   
          Header always set Access-Control-Allow-Methods "POST, GET, PUT, OPTIONS, PATCH, DELETE" 
          Header always set Access-Control-Allow-Headers "X-Accept-Charset,X-Accept,Content-Type"
          # RewriteEngine On                  
          RewriteCond %{REQUEST_METHOD} OPTIONS 
          RewriteRule ^(.*)$ $1 [R=200,L,E=HTTP_ORIGIN:%{HTTP:ORIGIN}]]
          
          # with AJAX withCredentials=true (cookies sent, SSL allowed...)
          SetEnvIfNoCase ORIGIN (.*) ORIGIN=$1
          Header always set Access-Control-Allow-Methods "POST, GET, PUT, OPTIONS, PATCH, DELETE" 
          Header always set Access-Control-Allow-Origin "%{ORIGIN}e"
          Header always set Access-Control-Allow-Credentials "true"
          Header always set Access-Control-Allow-Headers "X-Accept-Charset,X-Accept,Content-Type"
          RewriteEngine On
          RewriteCond %{REQUEST_METHOD} OPTIONS
          RewriteRule ^(.*)$ $1 [R=200,L,E=HTTP_ORIGIN:%{HTTP:ORIGIN}]
          
          


          When I post wrong username or password to the "login.html" page I receive just what is expected:
          "{"success":false,"message":"The username or password you entered is incorrect. Please check the username, re-type the password, and try again.","total":0,"errors":[],"object":[]}".

          When I post the right credentials, the response is an error:
          "Fatal error: Call to a member function get() on null in...". The error is on this line:
          $user['id'] = $modx->user->get('id');


          Thies means, that the user authenticates right: "$response->response['success'] == 1", but I have no access to the "$modx->user" object. ( $modx->user->get('id') ).

          So, may be the question should be: "How can I access the authenticated user object ($modx->user)" when my requests are cross domain?

          There is a good tutorial about using processors in the frontend here: http://ridcully.dunnock.modxcloud.com/records/2014/07/08/using-custom-processors-in-modx-revolution-over-ajax-request/, but the authentication is not cross-site.
            • 3749
            • 24,544 Posts
            The login processor doesn't know that it's a cross-domain request, so I don't think that's your problem. The only thing I can think of is that addSessionContext() logs the user in, but $modx->user isn't set until the next request. Looking at the addSessionContext() code, it doesn't appear to set $modx->user.

            In any event, you have the username in your snippet, so you can get the user yourself (assuming that the username is unique):

            $user = array();
            $username = $modx->sanitizeString($_POST['username']);
            $usr = $modx->getObject('modUser', array('username' => $username));
            
            $user['id'] = $usr->get('id');
            $profile = $modx->usr->getOne('Profile');
            $user['fullname'] = $profile->get('fullname');
            $user['email'] = $profile->get('email');


            If you care about speed or the site will get lots of logins this way, you can use getObjectGraph() to get the user information in a single query.

            You're probably aware of this, but you're open to brute force attempts to login, since you're bypassing the login screen. You'll want to secure the request by sending a token along that's a hash of the username + something else and test it in your snippet.
              Did I help you? Buy me a beer
              Get my Book: MODX:The Official Guide
              MODX info for everyone: http://bobsguides.com/modx.html
              My MODX Extras
              Bob's Guides is now hosted at A2 MODX Hosting