Authentication
Authentication represents the process where users or clients confirm they're identity with the application. The authentication process follows a certain number of steps to finally generate a Token. This token represents the access the current user or client has.
#
Authentication processAuthentication is handled by 'Authenticators'. Implementing the Swift\Security\Authentication\Authenticator\AuthenticatorInterface
. Take a look a REST User Authenticator for example:
A very important note is that the authentication process takes place before actually executing the Request a Controller. By the time a Controller method gets called Authentication has already finished. Authentication therefore NEVER takes place in a Controller. A controller however can still define Authentication Endpoints and return it's reponse. More on this later.
The authentication process is directed by an Authentication Manager. This manager checks all Authenticators whether the 'support' the given request. Once a Authenticator claims it support the Request, this Authenticator will be executed. No other Authenticator will be searched for nor authenticated against.
#
PassportOnce the authenticator claims to support the request (for example credentials have been found in the header) the Authentication Manager will call the authenticate method which is supposed to return a Passport representing the User or Client trying to authentication. This can be the default Swift\Security\Authentication\Passport\Passport
or any class implementing the Swift\Security\Authentication\Passport\PassportInterface
. This passport contains the User (implementation of Swift\Security\User\UserInterface
) that is found based on the Request and should contain and instance of Swift\Security\Authentication\Passport\Credentials\CredentialsInterface
. The Passport calls validateCredentials()
on this credentials to validate whether the provided credentials in the Request match the ones belonging the User on the Passport.
#
StampsA Passport can be enriched with Stamps Swift\Security\Authentication\Passport\Stamp\StampInterface
. This could for example tell that Authentication is already okay in case of a valid Bearer token. Take a look a AccessTokenAuthenticator::authenticate()
for example:
#
AttributesBesides Stamps there's also attributes that can be passed. This is no more, and no less than simple metadata that can shipped with the Passport. This could be useful for passing state or redirect data in case of Oauth authentication for example.
#
Token (Visa)After the Passport has been created in the authentication the Authenticator will be passed the Passport to createAuthenticatedToken( PassportInterface $passport ): TokenInterface
to create a token based on this Passport. This token should implement Swift\Security\Authentication\Token\TokenInterface
and plays an important role on the application to provide the authentication user, it's scope, whether the user is authenticated. whether authentication has expired, etc.
In this scope of Passports and Stamps it would make more sense to name a Token a 'Visa', however since 'Token' is generally accepted, this is the term that will be used.
#
EventsDuring Authentication several events are dispatched to patch into to append additional data, deny a Request access and more.
#
Entry pointsSince authentication occurs before a route is executed a user could potentially authenticate against any valid uri. This is not desirable as that might lead to unwanted behaviour, and besides a lot of unclarity for end users.
One possible solution to this issue is to check the route in the supports method of the authenticator and return false if the uri is not as desired. This works!
Another solution is to 'protect' the authenticator by having it implement Swift\Security\Authentication\Authenticator\AuthenticatorEntrypointInterface
. This will only allow the authenticator on Entry Point Routes. All Swift's default authenticators implement this except for the AccessTokenAuthenticator as this is not bound to a specific route.
#
Entry point routesA route can marked as being an Entry Point by added the ENTRY_POINT tag as in the example below.
Also note that authentication has already finished when we get to the controller. We simply just get the user and return it. Also, we require the user to be authenticated directly. When a user is authenticated using a token retrieved by an earlier login this will not be true. This way we make sure we're dealing with a 'fresh' authentication.
#
Fetching the Token or User in ServiceBy injecting the Swift\Security\Security
class you will be able to fetch the Token, User and Passport in any Service. Note that it's not possible to inject those directly as these are not available yet at Container Compilation time.
#
Fetching the Token or User in ControllerA Controller is by default already provided with the Security class through $this->security
. However, there's some handy shortcuts:
$this->getSecurityToken()
// The authenticated token$this->getCurrentUser()
// The currently authenticated user (or NullUser)
There is no shortcut for the Passport as this is mainly relevant during Authentication before a token has been granted.