Search code examples
laraveloauth-2.0google-oauthsingle-page-applicationlaravel-socialite

SPA OAuth2 social sign in - can you directly link to provider instead of redirecting?


I have a SPA that uses Laravel Sanctum for authentication. I am implementing OAuth2 social sign in.

In a server side rendered application this is how social sign in would work:

  1. User submits a form that makes a GET request to an action on a controller. The controller then redirects the user to the provider sign in page.
  2. User signs in with the provider and then is redirected back to the provided redirect URL.
  3. Redirect URL makes a GET request to another action on the controller. Controller makes a POST request to the provider with the code that is returned in the query string. If POST request is successful the user is authenticated.

In my SPA application this is how I currently have social sign in working:

  1. User clicks an anchor tag that takes them to the provider sign in page.
  2. User signs in with the provider and then is redirected back to the provided redirect URL which is a SPA page.
  3. SPA grabs the code from the query string and then makes an API request to the backend.
  4. The backend makes a POST request to the provider with the code. If POST request is successful the user is authenticated.

Are there any security concerns with directly linking to the provider sign in page (step 1) instead of redirecting from the backend?

Thanks in advance!


Solution

  • AFAIK there is no safe and standards-compliant way to implement OAuth 2.0 with a direct link to the authorization server's login page. Letting a protected server redirect to the login page is a fundamental security feature of the OAuth 2.0 flow appropriate for SPAs.

    Nowadays, the recommended OAuth 2.0 Flow for SPAs is the Authorization Code Flow with Proof Key for Code Exchange (PKCE). Other methods, namely the implicit grant, which you may have in mind, have been deprecated. It seems that Laravel Sanctum does not support OAuth login while Laravel Passport does explicitly support PKCE. For 3rd-party PKCE OAuth provider integration with Laravel (aka "Social Login"), see this Socialite PR/thread.

    Auth0 has a nice diagram graphically depicting the full Authorization Code Flow with PKCE.

    As you can see, you are required to construct a dynamic link (or background XHR/fetch-request) that includes several query parameters, some of them generated on-the-fly in your SPA (e.g. a code verifier and challenge), others originating from the server (e.g. state) and again others may either come from the server or may be hard-coded into your app (e.g. client id, redirect URI and scope).

    It is strongly recommended to add the state parameter, to protect yourself from Cross Site Request Forgery (CSRF) which is another reason why a static link will not be sufficient. See draft-ietf-oauth-security-topics-09, Section 2.1 for how to protect redirection and draft-ietf-oauth-security-topics-09 for more details on CSRF attack mitigation in the context of OAuth 2.0.

    I hope I convinced you by now that it is probably not a good idea to implement OAuth flows yourself from scratch. It is much too easy to get it wrong. I strongly recommend you use a ready-made and peer-reviewed JavaScript library instead. Any good OAuth provider will probably have one preconfigured for their service. Otherwise you'll find several generic options on npm. I don't know Socialite well enough to decide whether their implementation of PKCE is ready for production.