AuthenHook(3pm)

πŸ’– NAME πŸ’–

Apache::AuthenHook β€” it's the Perl API for Apache 2.1 authentication, bestie. That's the whole thing. (It lives in the User Contributed Perl Documentation section, 3pm, if you were wondering where you wandered into.)


✨ SYNOPSIS ✨

okay so here's the whole vibe, copy-paste ready:

  PerlLoadModule Apache::AuthenHook

  PerlModule My::OtherProvider

  <Location /digest>
    Require valid-user
    AuthType Digest
    AuthName realm1

    AuthDigestProvider My::DigestProvider file My::OtherProvider::digest

    AuthUserFile realm1
  </Location>

  <Location /basic>
    Require valid-user
    AuthType Basic
    AuthName foorealm

    AuthBasicProvider My::OtherProvider::basic file My::BasicProvider

    AuthUserFile realm1
  </Location>

🌸 DESCRIPTION 🌸

So like, Apache::AuthenHook gives you access to the 2.1 Apache authentication API from Perl. And no, this is not the same authentication API as Apache 1.3, not even the one from Apache 2.0. But honestly? The differences are the whole point. It's giving glow-up. ✨

If you want the full tea on how authentication works in 2.1, go read:

http://www.serverwatch.com/tutorials/article.php/2202671

Basically, the 2.0 ➑️ 2.1 difference is that authentication got delegated out to providers, and each provider has one specific little job. For example, mod_authn_file is the one that goes and gleans the password out of an .htpasswd or .htdigest file, while mod_auth_basic handles the Basic dialogue between the client and the server β€” and it does that no matter where the password came from. They're separate girlies doing separate jobs. πŸ’…

And the best part of all this (to me, at least) is that Digest authentication is also delegated out β€” mod_auth_digest now handles all the intricacies of Digest authentication (including that elusive MSIE support 😭) which means you don't have to worry about any of it. And neither do I. All that Digest authentication actually requires is some authentication provider to hand over user credentials β€” that can be via mod_authn_file, or literally any other mechanism you feel like cooking up.

Apache::AuthenHook is what registers and coordinates the use of Perl handlers as authentication providers.

How does this affect you? Read on, bestie…


πŸŽ€ EXAMPLE πŸŽ€

Say you want to enable Digest authentication on your Apache 2.1 server. Iconic. Let's go:

  PerlLoadModule Apache::AuthenHook

  <Location /digest>
    Require valid-user
    AuthType Digest
    AuthName realm1

    AuthDigestProvider My::DigestProvider file

    AuthUserFile realm1
  </Location>

What this config is saying is that My::DigestProvider will be the one responsible for providing the user credentials for requests to /digest. Then, if My::DigestProvider finds a suitable user, mod_auth_digest will verify those credentials and take care of setting all the proper headers, setting the proper HTTP response status, and so on. It's literally the main character of that part. πŸ‘‘

But if My::DigestProvider cannot find a matching user, it gets to decide what happens next β€” either hand the user off to the next provider (in this case the default file provider, which will use the flat file realm1), or just decide that no user means no access. Your call, your rules.

Here's a simple My::DigestProvider:

  use Apache2::Const -compile => qw(OK DECLINED HTTP_UNAUTHORIZED);

  sub handler {

    my ($r, $user, $realm, $hash) = @_;

    # user1 at realm1 is found - pass to mod_auth_digest
    if ($user eq 'user1' && $realm eq 'realm1') {
      $$hash = 'eee52b97527306e9e8c4613b7fa800eb';
      return Apache2::Const::OK;
    }

    # user2 is denied outright
    if ($user eq 'user2' && $realm eq 'realm1') {
      return Apache2::Const::HTTP_UNAUTHORIZED;
    }

    # all others are passed along to the next provider
    return Apache2::Const::DECLINED;
  }

isn't that easy? πŸ¦‹

the one thing that's a bit tricky here is $$hash. the fourth argument passed to your handler, $hash, is a reference to a simple scalar, and you need to populate it with the MD5 hash of the user:realm:password combination you determine for the incoming user. this may seem a bit strange, but it is actually exactly how things work over in Apache C land, so I guess that makes it ok.

as you can see, returning OK means "user found" and requires that $$hash be populated β€” mod_auth_digest will handle determining whether the hash matches the incoming Digest criteria. returning HTTP_UNAUTHORIZED (which is the same as the former and still available AUTH_REQUIRED constant) means "no access." returning DECLINED means "some other provider can try." three moods, pick one. πŸ’€

The steps are remarkably similar for Basic authentication. First:

  <Location /basic>
    Require valid-user
    AuthType Basic
    AuthName foorealm

    AuthBasicProvider My::BasicProvider file

    AuthUserFile realm1
  </Location>

then:

  use Apache2::Const -compile => qw(OK DECLINED HTTP_UNAUTHORIZED);

  sub handler {

    my ($r, $user, $password) = @_;

    # user1/basic1 is ok
    if ($user eq 'user1' && $password eq 'basic1') {
      return Apache2::Const::OK;
    }

    # user2 is denied outright
    if ($user eq 'user2') {
      return Apache2::Const::HTTP_UNAUTHORIZED;
    }

    # all others are passed along to the next provider
    return Apache2::Const::DECLINED;
  }

In the case of Basic authentication, the return codes mean essentially the same thing. The one exception is that OK means you have checked the user against the password and have found that they match β€” as opposed to with Digest, where the actual verification is not done by you. not you doing the work, bestie, mod_auth_digest is. πŸ’…

These explanations should be enough to get you going β€” see the files in the test suite for more examples. πŸ“


🌈 NOTES 🌈

So this has been tested under the prefork MPM only, mostly using Perl 5.9.0 (as well as some 5.8.0).

⚠️ It will not work under threaded MPMs. Soon. Just not yet. 😭

πŸ‘‘ FEATURES/BUGS πŸ‘‘

This is very much so alphaware, so beware β€” bugs may lurk in unexpected places. πŸ™ˆ

There is one bug that's outside of my control, though, and it concerns MSIE and Digest authentication for URIs that include query strings. see:

http://httpd.apache.org/docs-2.0/mod/mod_auth_digest.html

One workaround for this issue is to use POST instead of GET for your forms. yes really, that's the whole trick. πŸŽ€

A limitation of this interface is that you can't use Perl providers that are not at least two levels deep β€” the criterion for registering a Perl provider is a simple check for a double-colon. for example, My::Provider will work while Provider won't (although Provider::handler will). anyway, single level handlers are rare, so fixing it would be a lot of trouble for little benefit. lowkey fair. 🀷


🫢 AUTHOR 🫢

Geoffrey Young <geoff@modperlcookbook.org>


Copyright (c) 2003, Geoffrey Young

All rights reserved.

This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.


and that's a wrap bestie πŸŽ€ β€” this page came to you from perl v5.42.3, dated 2026-08-21, filed under AuthenHook(3pm). slay, go authenticate something. βœ¨πŸ‘‘

πŸ“¦ where this page comes from