Laravel API Authentication for Social Networks — OAuth2 Social GrantSocial network authentication for your first-party apps using Laravel PassportOrobo LuckyBlockedUnblockFollowFollowingApr 11Image by Gerd Altmann from PixabaySocial networks have become an essential part of our online presence, more and more apps are integrating with popular social networking providers like Google and Twitter to authenticate their users and authorize access to resources.
The list of social providers is growing and the need to integrate them into our applications is increasing.
In this article, we’ll explore how to build an OAuth2 Social Network Grant in Laravel Passport.
This will enable users to authenticate on your APIs with their social network accounts.
Before we begin, this article assumes that you’re familiar with OAuth2 and understand how Laravel Passport works.
If you aren’t or haven’t used Passport, the Laravel documentation is a great place to start.
Laravel Passport – Laravel – The PHP Framework For Web ArtisansLaravel – The PHP framework for web artisans.
comQuick Refresher on OAuth TermsResource Owner: the entity that can grant access to a protected resource.
Typically this is the end-user.
Client: an application requesting access to a protected resource on behalf of the Resource Owner.
Resource Server: the server hosting the protected resources.
This is the API ServerAuthorization Server: the server that authenticates the Resource Owner and issues Access Tokens after getting proper authorizationAccess Token: a token used to access protected resources on the resource server.
ContextThe OAuth2 specification defines and describes a number of ways for client applications to obtain access tokens.
This tokens essentially identifies a user’s permission to access protected resources.
These methods of obtaining access tokens defined by the specification are called Grants.
Each of these grants has specific use-cases and are only suitable for use in the context in which they’ve been defined.
The specification doesn’t exactly define a Social Network context but it does define one that’s close enough for our use-case —Resource owner credentials grant for trusted first-party clients.
Going forward, the terms Resource-owner and User would be used interchangeably.
Traditionally, to authenticate users on your APIs for your first-party clients you’ll want to use the Resource-owner Credentials Grant.
This allows your users to authenticate by providing their credentials (usually username and password) to obtain a token.
Let’s take a look at the request format for obtaining a token using this grant.
The client sends a POST request with the following body parameters to the authorization server:grant_type with value passwordclient_id with the client’s IDclient_secret with the client’s secretusername with the user’s usernamepassword with the user’s passwordscope with a list of scope separated by spaces.
You’ll notice that this grant accepts a client_secret but there’s a security concern about first-party clients like native apps and SPAs that can’t store this securely.
The security implications of this is beyond the scope of this article but there are ways to mitigate this such as using a proxied backend to interface with the authorization server.
However, for the purpose of demonstrating the idea behind this article, we’ll assume that the first-party client can keep a secret.
For social networks, using a username and a password as credentials would be counterintuitive and defeats the entire purpose of integrating social authentication in the first place.
As mentioned earlier, the specification doesn’t define a Social Network Grant so we’ll be implementing one ourselves.
Social Network GrantTo create our social network grant, we can tailor the Resource-owner Credentials Grant to fit our use-case and build the grant off of its structure.
Let’s define the typical authentication flow when working with social network authentication, this will inform us on how to tailor the authorization grant and identify elements that would be candidates for credentials.
The FlowThe client makes a request to the social network provider (Google for example)The user authenticates on the provider and gets an ephemeral access code that would be used to obtain a tokenThe client exchanges the code for an access token and may now use the access token to access protected resources on the social network provider within the requested scopes.
However, the access token obtained in the last step is only valid for the social network provider, it can’t be used to access protected resources on our resource server.
Since we effectively now act as an authorization server, we need a way to authenticate the user and issue them access tokens that are valid on our resource server.
At the end of the authentication flow above, we ended up with an access token that essentially represents the user trying to access our API.
This access token can now become part of the User’s credentials.
But the access token in itself is pretty much useless we know which social network provider it’s authorized for.
The network provider and the access token obtained from the provider are two good candidates for a User’s credentials.
Now that we’ve identified what elements should make up credentials in a social network context, we can now go ahead and define the request structure for obtaining access tokens from our authorization server using our bespoke grant:grant_type with value socialclient_id with the client’s IDclient_secret with the client’s secretprovider with the name of the social provideraccess_token with the access token from the social providerscope with a list of scope separated by spaces.
Below is a graphic illustration of the authentication process:ImplementationWe’ve now defined something of an acceptable structure for the authentication request to obtain an access token from our authorization server and we can go ahead and implement this grant.
To get started, we’ll install the Laravel passport package.
Passport will act as a bridge to help us manage our clients, generate access tokens and authorize requests into our API.
(See installation for instructions) We’ll also be needing the Laravel Socialite package to help us validate the User on various social networks.
Once we’ve installed and configured Laravel passport and socialite, the next logical step is to create our Social Grant and enable it on the authorization server so that it can respond to access token requests.
Grants in the authorization server implement the respondToAccessTokenRequest method, this method handles requests for access tokens for the specified grant.
For our purpose, the validateUser method is the most important.
Within this grant, we need a way to retrieve the User by their access token, this means validating their credentials.
This grant depends on a SocialUserProvider that validates the given access token from the social network provider against the social network provider.
The validateUser method returns an instance of UserEntityInterface or throws an OAuthServerException if the access token is invalid.
The SocialUserProvider implements a SocialUserProviderInterface.
The interface declares a single method getUserEntityByAccessToken that retrieves the social user from the provider:The SocialUserProvider Implementation:First, we attempt to retrieve the user from the social network provider by their access token using Laravel Socialite.
If this operation is successful, we’ll convert the user from the social network provider into a resource owner on our resource server and return the entity back out to the authorization server.
We throw an OAuthServerException exception if the operation isn’t successful.
Next, we define the UserRepository implementation on our resource server to retrieve or create a resource owner from a social user:Finally, we will enable this grant on the authorization server from a service provider so that it can respond to access token requests:The authorization server can now issue new access and refresh tokens to the resource owner and the authentication flow is complete.
Requesting All ScopesWhen you authenticate users on your first-party clients, you may want to authorize the access token for all scopes that are supported by the application.
This is particularly true for resource-owner credentials and client credentials grants.
Since our social grant is something of a resource-owner credentials grant, we can enable this behavior on the authorization server so that it can grant all scopes to this grant type on request.
To do this, we will extend the ScopeRepository implemented by Laravel passport on the authorization server, override the finalizeScopes method and inject the modified ScopeRepository on the grant.
The finalizeScopes method on the ScopeRepository filters the scope against the ones supported by the application and also based on the grant type:We essentially just let requests for all scopes fall through to Passport and let it handle checking the scopes.
Passport will allow all scopes if the scope is an asterisk *.
The can method on the token instance on the resource server will always return true for this scope.
Since we don’t want to allow this behavior on all grant types on the authorization server but the Social Grant, we will only set it on that grant when we enable the grant in the service provider:The code is available on Github if you’re interested.
orobogenius/laravel-oauth2-social-grant-demoAuthenticate Social Users on your OAuth2 Server using Laravel Passport – orobogenius/laravel-oauth2-social-grant-demogithub.
comConclusionWe’ve talked about how to authenticate social network users on your OAuth server from first-party applications.
This is achieved by creating and enabling a Social Grant type on the authorization server.
In practice, this solution is not limited to OAuth, it can also be used outside the context of OAuth to authenticate social network users on your API.
The key elements are the Social Network Provider and the Access Token from the provider which would be used to validate users on the provider before issuing access tokens (and refresh tokens) to them.
Thanks for reading and I hope that this article was helpful.