Using hook_menu() and hook_permission() to control access How does one limit "what" can access a page. I understand how to use hook_permission() to set user permission based on a role to control access to hook_menu() items. However, what if I have a hook_menu() item that is to be used solely by the system itself? For example, say I have a registration page in a custom module: module/register - Anyone can access that page. Then, say I have an ajax call that is to be made when the user performs some action on the page. So, I register another item in hook_menu(), call it module/register/ajax - I do not want anyone to be able to browse to module/register/ajax but I want to be able to do an ajax call to that page. What is the best way to accomplish this?

I have used AJAX callbacks but this is not a case where a form is being submitted. This is just a pure AJAX call from JavaScript on an event after the page loads.
Quick and dirty, you could do something like this:

function YOURMODULE_menu() {

  $items=array();

  $items['YOURMODULE/register/ajax'] = array(
    'page callback' =&gt; 'YOURMODULE_register_ajax',
    'access callback' =&gt; 'YOURMODULE_access_ajax',
    'type' =&gt; MENU_CALLBACK,
  );

  // other $items here...

}


and then define you own access function for ajax like this:

function YOURMODULE_access_ajax() {

  if (user_is_logged_in() &amp;&amp; $_SERVER['REQUEST_METHOD']=='POST') {
    return TRUE;
  } else {
    return FALSE;
  }

}


which will grant access to the path only if the user is logged in and is using POST to access it.  The key here is when you surf around, you are using GET, but when using AJAX, most of the time at least, you are using POST.  Now, if you wanted to get more fancy other than just if the user is logged in, you could do more with user_access() in there instead of the simple user_is_logged_in().

IF however, you are using GET for your AJAX, you can in your page callback check the parameters and if they don't validate, return MENU_NOT_FOUND; or return MENU_ACCESS_DENIED; instead of the drupal_json() stuff.