I recently had a client that began delegating access to all of its data assets across the enterprise network via OAuth, specifically the OAuth 2.0 protocol. While I was there architecting a Drupal solution as their new Web platform, they wanted me to hook into this system to authenticate their Drupal users. Although there have been some modules available in the ecosystem to support OAuth2, there weren’t any available to provide this functionality. So I created the OAuth2 Authentication module.
This module allows users to log into a Drupal site authenticating against a remote identity provider (IDP) via OAuth2. That is, if a user’s credentials can be used to retrieve a valid access token, he/she will be logged into the site with those credentials and the token will be added to his/her session. If the user account doesn’t exist yet, it will be created.
In doing this, we’re making the assumption that resource requesters are actually resource owners. Generally, one shouldn’t make that assumption as OAuth2 is an authorization mechanism, not an authentication mechanism. Ideally, logging in users via OAuth2 should be done with OpenID Connect. It provides a proper identity layer on top of OAuth2. It’s essentially the evolution of SAML; see my answer to Can OAuth 2 be used for SSO? Or do I need a more sophisticated authentication? for details. In situations where one doesn’t have access to an OpenID Connect server, but does have access to an IDP that speaks OAuth2 and can trust the environment in which all of it operates, this module is sufficient.
The security implications of using this module should be well understood. If one doesn’t control the environment in which it’s running, then it shouldn’t be used. For example, I don’t recommend running with this concept in a mobile environment as it can’t be trusted to the same extent as a Drupal site behind a corporate firewall. The following articles are on the subject are noteworthy:
It also wouldn’t hurt to study the official OAuth 2.0 Threat Model and Security Considerations.
Initial Set-Up
- Install and enable the OAuth2 Client and OAuth2 Authentication modules as you would any other.
- If you wish to override any of the methods in the OAuth2AuthenticationClient class to change the module’s behaviour, create another class that extends it and implement the desired methods. This is best done in a custom module for your site, something like Sitename Authentication (sitename_authentication) where S/sitename is the name of your site.
- Surf to the configuration page over at Home » Administration » Configuration » Web services » OAuth2 Authentication to configure your token endpoint. This section is mandatory while the others are optional. They contain sane defaults, but look over all of it to make sure it’s what you need for your set-up.
- If you subclassed OAuth2AuthenticationClient, replace the default class name in Miscellaneous Settings » Client Class with the name of your new class.
- Hit the Save configuration button to save your settings.
- Enjoy!
Notes
- Once you’ve got this set up, you’ll have to ensure that the Web-services client module you’re using supports the OAuth2 protocol (i.e., token access to resources). If you’re already using one that doesn’t, you’ll have to add that support. Otherwise, go with one that supports this already.
- When an existing local user logs in, the module will attempt to get an access token for him/her. On success, the token will be added to the user’s session. On failure, the user will still be logged in, but will not get a token. Whenever a request to get a token is made, the results are reported in the log.
- If an existing user whose password has changed on the IDP, but not Drupal yet, logs in, the password hash stored locally will be updated. This is attempted after a local login failure: If the user can authenticate remotely, the account is updated locally, and the user is logged in normally. There are no noticeable differences to the end user.
Issues
Token Expiration
If the total expiration time for your tokens, including successive tokens returned by your token server through refresh tokens (RTs), is less than the maximum time a user can be logged in (see Session Expire for details), users will still be logged in when their final tokens expire.
As this module doesn’t (yet) deal with that situation, you’ll need to come up with a solution that meets your requirements. Some background information on this can be found over at Best-Practice for dealing with OAuth 2.0 Token expiration at the Consumer.
Options
- Automatically log out each user after being logged in for the token expiry time.
- Extend the token expiration time to the maximum amount of time a user can be logged in.
- Add support for refresh tokens (RTs) that can keep working until a user’s login session expires.
- Have the token server issue tokens that don’t expire.
- Some combination of the above.
Real-World Solutions
- Facebook: Access Tokens
- LinkedIn: Handling Errors & Invalid Tokens
- Box: OAuth2 update - Longer lived refresh tokens
- Salesforce: Understanding the OAuth Refresh Token Process
Helpful Drupal Modules
- Session expire (also explains the default login session length)
- Automated Logout
- Ejector Seat
Similar Modules
OAuth2 Login redirects users to another Drupal site for authentication, and then sends them back logged in once they’re authenticated. This module doesn’t do any redirection; everything is done behind the scenes. Users logging in won’t even know that they’re authenticating against another system. They simply log in using the normal Drupal login process, but get an access token on top of that (if granted). Users that don’t exist locally will be created during the login process.
In conclusion, although this solution isn’t the most appropriate given the technology that’s now available, it does fit a lot of real-world use cases. At the time of this writing, there are 130 sites using it. This is quite impressive given that I recommend against it on the project page!