Understanding Simple OAuth in Drupal: Authentication for Decoupled Applications
What is Simple OAuth?
Simple OAuth is a Drupal module that provides authentication capabilities for decoupled applications. It implements token-based authentication, allowing users to securely access your application through access tokens rather than traditional login credentials.
Token-Based Authentication Flow
The authentication process follows a hierarchical token system:
- Access Token: The primary authentication credential, generated as a unique SHA-256 hash
- Refresh Token: Used to generate new access tokens when they expire
- Base Authentication: Required when both access and refresh tokens expire
Understanding Access Tokens
Access tokens are JWT (JSON Web Tokens) that contain two key components:
Claims
Claims store essential user identity information needed by the client application. By default, Simple OAuth includes two claims:
- `mail`: User's email address
- `username`: User's account name
Scopes
Scopes represent user roles within your application. They determine what actions a user can perform. Some important points about scopes:
- Multiple roles should be specified with space separation
- If no scope is defined, the 'authenticated' role becomes the default
- The final token includes both requested scopes and any additional roles defined in the client ID
Extending Access Token Claims
To add custom claims beyond the default `mail` and `username`, you need to extend the `AccessTokenEntity` class. Here's how:
class MyAccessTokenEntity extends AccessTokenEntity {
public function convertToJWT(CryptKey $privateKey) {
$private_claims = [];
\Drupal::moduleHandler()
->alter('simple_oauth_private_claims', $private_claims, $this);
if (!is_array($private_claims)) {
$message = 'An implementation of hook_simple_oauth_private_claims_alter '
. 'returns an invalid $private_claims value. $private_claims '
. 'must be an array.';
throw new \InvalidArgumentException($message);
}
$builder = (new Builder())
->setAudience($this->getClient()->getIdentifier())
->setId($this->getIdentifier(), TRUE)
->setIssuedAt(time())
->setNotBefore(time())
->setExpiration($this->getExpiryDateTime()->getTimestamp())
->setSubject($this->getUserIdentifier())
->set('scopes', $this->getScopes());
// Add custom claims here
// Example: $builder->set('user_picture', ...);
foreach ($private_claims as $claim_name => $value) {
$builder->set($claim_name, $value);
}
$key = new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase());
$token = $builder->sign(new Sha256(), $key)->getToken();
return $token;
}
}
Implementing the Custom Token Entity
To use your custom token entity, you'll need to register it with Drupal's service container:
class MyServiceProvider extends ServiceProviderBase implements ServiceProviderInterface {
public function alter(ContainerBuilder $container) {
$definition = $container->getDefinition('simple_oauth.repositories.access_token');
$definition->setClass('Drupal\my_module\Repositories\MyAccessTokenRepository');
}
}
Best Practices
- Always validate private claims before processing
- Consider token expiration times carefully for your use case
- Implement proper error handling for token generation and validation
- Document any custom claims added to the system
- Monitor token usage and implement rate limiting if necessary
Reach back to us if you need any help.