Symfony’s Security Key Concepts in 5 minutes

Let’s go over the obscure terms and concepts of this critical component

Photo by JESUS ECA on Unsplash

Can I have 5 minutes of your time? That’s all I need to help you step up about Symfony 6 Security component. It’s sometimes hard to understand everything in here. Well, you don’t have to understand everything of course. But having the knowledge of the different parts and terms used will significantly help you understanding what you’re doing. Without waiting furthermore, let’s get into it.

User, password and roles

Everything begins with users. Symfony offers a UserInterface you can implement so your model is compatible with the security layer and match your exact needs. An user has an unique identifier to differentiate it from other users. This identifier can be anything you want: an integer, an email, an UUID. It’s up to you.

An user is also attached to one or multiple roles. These roles are used afterwards to make decisions on resources access. Roles can be organised hierarchically. This means if you have a role, you can inherit of other roles. For instance, a super admin user is likely to have all the defined roles in your application. Finally, a PasswordHasher is used to encrypt passwords.

More about the User concept:

User Providers

Your application can contain multiple ones. The main goal of the user provider is to load a user from somewhere thanks to its unique identifier. What I mean by “somewhere” is it is up to you to choose where to store your users. In most cases it will be in database. But your users can also be stored in an LDAP server, or you may use socials to log your users thanks to Google, Facebook, Apple, etc. Each way of loading an user should be attached to one different user provider. This way, if anything happens with one way to load users, the other ways won’t be affected.

If you want to have multiple providers to be used at once, this can be done by the so-called chain user provider, which allows you to merge multiple providers as one. This way, the Security component will try to load the user from each provider of the chain until it can load a valid user.

More about the User Provider concept:

Firewalls

A firewall defines which provider to use for which part of the application. You may use a firewall for the front application, and another firewall for the administration back office. You can do this by defining URL patterns to match to go through a specific firewall. For instance, the firewall concerning the back office will be used on all URL starting with /admin. You are allowed to use the power of regexes to define URL patterns. Also, a firewall can be:

  • Stateful: the logged in user is stored in session and there’s no need to send credentials at every request ;
  • Stateless: the logged in user isn’t stored and credentials need to be sent at every request. This is useful in APIs, when using an API key.

You can define as many firewalls you need, but do it with caution: it can be difficult to debug an application with tons of firewalls.

More about the Firewall concept:

Voters and ACL

Having a firewall telling which part of the application is secured with a particular provider is cool, but it isn’t enough. You need to create Access Control Lists and do precise decisions on which precise resource can be accessed by which precise user or group of users. This is done thanks to voters. Generally, a voter supports only one resource. The voter receives the user who wants to access the resource, the resource itself and an attribute. The attribute is somehow the action to perform on the resource by the user: view it, delete it, edit it, etc. It can be anything you want.

Voters can make great use of an authorization checker, which checks that a user has a particular role. What makes it powerful is it will go through the whole hierarchy of roles to do so.

More about the Voter concept:

Authenticators, passports and badges

The role of an authenticator is to tell if, for a given request, all information to authenticate an user are available. To do so, the authenticator have to indicate if it supports the current request (e.g. does the request contain the right headers to proceed?). If yes, then the authenticate method of the supporting authenticator will be called. Otherwise, if the authenticator doesn’t support the current request, it will abstain from doing anything and will be skipped. If other authenticators are configured, the Security component will proceed to them, until it finds an authenticator that actually support the request.

During the call of authenticate, two things can happen:

  • An error occurred (e.g. the API key defined in the request is empty). An AuthenticationException is raised and the authenticator won’t proceed further. The authentication is a failure, and the onAuthenticationFailure of the authenticator is called to define the behavior to adopt (e.g. a HTTP 403 response) ;
  • The request has all it needs to proceed. A new Passport will be created. The authentication is a success, and the onAuthenticationSuccess of the authenticator is called to define the behavior to adopt, like redirecting the user on its last page.

The newly created Passport will contain credentials and the so-called Badges. These badges tell the Security component how to behave when processing the passport during the authentication process.

Photo by ConvertKit on Unsplash

For example, there is a RememberMeBadge to tell the component you want this passport the have the famous “Remember Me” feature. The UserBadge tells that a user unique identifier is present in the passport, and it will be used to retrieve the user thanks to configured user providers.

Once the passport is fully created, the Security component will have all necessary information and will now exactly how to authenticate the user in the application. You can attach as much badges as you want, as well as defining yours.

More on the Authenticator, Passport and Badge concepts:

And… time! We just covered the key concepts of the Security system of Symfony 6. It’s not that complicated and there is no black magic anywhere.

Of course there is so much to say about security in Symfony, like dispatched events to plug yourself at each authentication step, CSRF protection and so on. But we already seen many new concepts and I’m sure everything will be way more clear next time you’ll deal with security in your application!

--

--

--

SensioLabs is the creator of the Open-Source framework Symfony. SensioLabs supports companies using PHP and Symfony, with consultancy, expertise, services, training and support. Our team shares articles and opinions to start a conversation within the community.

Recommended from Medium

There’s a misunderstanding of what emotional unavailability looks like in action.

A Practical Approach to Choose the Right Python Framework

Parquet timestamp and Athena Query

Visual Wake Words on Arduino Nano

We set aspirational OKRs for Q1 2020.. and then COVID-19

The best package manager for macOS and a tutorial for Nix on macOS

Here’s a Shoutout to The (Clinically) Tired and Lazy

Automation using Jenkins Docker and Git

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alexandre Daubois

Alexandre Daubois

Symfony 6 Certified Developer (Expert) at SensioLabs

More from Medium

The love story between Symfony and HTTP

Symfony Station Communique — 7 January 2021. A look at Symfony and PHP news.

Designing a Symfony Validator - the TDD way 📝

A handsome, middle aged black man poking his temple. The image says “tests won’t fail if you have no tests”.

Serializing data in PHP II: A simple primer on database interactions