The two obvious choices are to either have Drupal use a third party user table, or to have third party software utilize the Drupal user table (Synchronization is covered in another section). This section will address how Drupal can be made to use an alternative user table.

The first thing to consider is whether you have an existing authentication system that you want to use. Enterprise environments may have directory services running on some LDAP product -- openLDAP, Novell eDirectory, Microsoft Active Directory, etc. If this is your situation, have a look at the LDAP Integration module. The module has its own documentation.

If you're not able to use a module as an assist, then read on.

There is a strategic location in includes/database.inc, where Drupal performs table prefix translation. By trapping the '{users}' you have the power to rewrite all Drupal users query, and can perform your own SQL rewrites.

This has the advantage of not modifying other Drupal files, or minimizing any needed edits.

Use something similar (and cleaner) to this code to perform your own user table query manipulation. This is used at the beginning of db_prefix_tables(), before Drupal performs any table translation.

if (strpos($sql, '{users}')) {

  if (eregi('^update', $sql)) {
    // someone installed a module that updates the user table
    // this is not supported, Issue and error, and quit.
    CallCustomException();
  }
  $DrupalUserSQL = array(
    '@{users}@i',
    '@= u.uid@i',
    '@=u.uid@i',
    '@u.uid =@i',
    '@u.uid=@i',
    '@u.uid@i',    // general selct
    '@u.uid@i',    // group by
    '@u.uid@i',    // order by
    '@u.name@i',   // group by
    '@u.name@i',   // order by
    '@u.pass@i',
    '@u.mail@i',
    '@u.language@i',
    '@u.picture@i',
    '@u.picture,@i',
    '@u.picture,@i',
    '@u.data@i',
    '@, u.data@i',
    '@u.data,@i',
    '@u.status@i');
  $ThirdPartyUserSQL = array(
    TABLE_PREFIX . 'user', // custom db prefix
    '= u.userid',
    '=u.userid',
    'u.userid =',
    'u.userid=',
    'u.userid as uid',
    'u.userid',
    'u.userid',
    'u.username',
    'u.username',
    'u.password',
    'u.email',
    'u.languageid',
    '1',         // removes group/order by picture, data, status, etc.
    '',
    '',
    '1',
    '',
    '',
    '2');

    if (strpos($sql, 'registered_name')) {
      $DrupalUserSQL = array_merge(array('@u.name AS registered_name@i') , $DrupalUserSQL);
      $ThirdPartyUserSQL = array_merge(array('u.username AS registered_name') , $ThirdPartyUserSQL);
    }
    else {
      $DrupalUserSQL = array_merge(array('@u.name@i') , $DrupalUserSQL);
      $ThirdPartyUserSQL = array_merge(array('u.username AS u.name') , $ThirdPartyUserSQL);
    }

    $sql = preg_replace($DrupalUserSQL, $ThirdPartyUserSQL, $sql, 1);

The exception/error thrown above is trap any locations during the development where the users table is being updated. It could remain there, to ensure all new modules have been tested or modified to handle user table updates.

Note that you will probably still need to edit or replace the user module, since allowing both Drupal and your third party application to administer users can have negative side effects.

Module_invoke and bootstrap

In case someone is interested, you can also call drupal functionality from an external php script using Drupal's module_invoke and drupal_bootstrap functions. So in addition to sharing the user base, you can do a lot to make their integration seamless to the user--display node content, blocks, etc. Just as an example, the following will grab a thumbnail from node #42 for use by your external, custom site.

require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$thumbnail = module_invoke('image','display', node_load(42), 'thumbnail');