Search code examples
phplaravelmatrixinertiajslaravel-socialite

Laravel Socialite dynamic server url for provider?


I am trying to add a provider for the new Matrix Auth protocol based on OIDC/OAuth2.0 which is outlined in https://areweoidcyet.com/

The major catch here is that since Matrix is selfhostable and federated there is no central user provider but rather endless. It is also not possible to have a config defined server since there might be users from different servers using a single service. I want to have a homeserver input field when someone tries to use this login to then query the right things and put in the correct URLs into the Provider functions. An example on how that works is in https://areweoidcyet.com/client-implementation-guide/

Essentially the user puts in their HS, the client (here the laravel app) then pulls in the well known and the auth_issuer data to figure out the right path.

This is clear to me. What however is not clear to me is how I can get the homeserver URL from the UI to my Provider in a non racy way. Is this even possible? For UI I am using Intertia and not blade. But I can likely transfer the knowledge from blade to my setup as well if needed.

Feel free to ask for further questions on this so I can get a good answer.


I had so far a look around various other answers and how to make providers but they all seem to expect a static url of the authentication provider. Which makes sense in your normal OAuth2 setup with central auth. However this is not a given in my usecase.

I have seen also suggestions to use a config value but thats racy. Others suggested a database model but I fear that this isnt very secure to let unauthenticated users write to the Database.


Solution

  • Since you cannot freely pass values ​​to the Socialite Provider, you have no choice but to use config.

    // Socialite Provider
    
        /**
         * {@inheritdoc}
         */
        protected function getAuthUrl($state): string
        {
            $url = config('services.matrix.url').'/authorize';
    
            return $this->buildAuthUrlFromBase($url, $state);
        }
    
        /**
         * {@inheritdoc}
         */
        protected function getTokenUrl(): string
        {
            return config('services.matrix.url').'/oauth2/token';
        }
    
    // Controller
    
        public function redirect(Request $request)
        {
            // Get the necessary information.
            // ...
    
            config(['services.matrix.url' => $url]);
            config(['services.matrix.client_id' => $client_id]);
            config(['services.matrix.client_secret' => $client_secret]);
    
            session(['matrix_url' => $url]);
            //...
    
            return Socialite::driver('matrix')->redirect();
        }
    
        public function callback(Request $request)
        {
            $url = session('matrix_url');
            // ...
    
            config(['services.matrix.url' => $url]);
            config(['services.matrix.client_id' => $client_id]);
            config(['services.matrix.client_secret' => $client_secret]);
    
            $user = Socialite::driver('matrix')->user();
    
            // ...
        }
    

    Edit

    A few months ago, Socialite added support for custom parameters, so you can use those too.

        protected function getAuthUrl($state): string
        {
            $url = $this->parameters['url'].'/authorize';
    
            return $this->buildAuthUrlFromBase($url, $state);
        }
    
    return Socialite::driver('matrix')->with(['url' => $url])->redirect();