Fosrestbundle: How does one authenticate a user via REST?

Created on 3 Jun 2014  路  12Comments  路  Source: FriendsOfSymfony/FOSRestBundle

In the view docs, regarding CSRF tokens, there's the following sentence:

This of course requires that REST API users authenticate themselves and get a special role assigned.

How would REST API users actually authenticate themselves? There's no example.

Most helpful comment

I am using traditional username/password authentication, but using custom headers.

I use this function in my controller to validate users.
*Note that I pass $this is passed as $context

    private function currentUser($context){
        $username = @$context->container->get('request')->headers->get("key");
        $password = @$context->container->get('request')->headers->get("secret");
        return $this->container->get('helper')->loginUser($username, $password);
    }

And I have this registered as a service

public function loginUser($username, $password){

        $securityContext = $this->container->get('security.context');
        if ($securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
            return $securityContext->getToken()->getUser();
        }

        /* Validate the User */
        $user_manager = $this->container->get('fos_user.user_manager');
        $factory = $this->container->get('security.encoder_factory');
        $user = $user_manager->loadUserByUsername($username);
        $encoder = $factory->getEncoder($user);
        $validated = $encoder->isPasswordValid($user->getPassword(),$password,$user->getSalt());
        if (!$validated) {
            http_response_code(400);
            echo "Validation Failed";
            exit;
        } else {
            $token = new UsernamePasswordToken($user, null, "main", $user->getRoles());
            $this->container->get("security.context")->setToken($token); //now the user is logged in

            //now dispatch the login event
            $request = $this->container->get("request");
            $event = new InteractiveLoginEvent($request, $token);
            $this->container->get("event_dispatcher")->dispatch("security.interactive_login", $event);

            return $user;
        }
    }

It is tested and working using both browser based and CURL based methods.

All 12 comments

Hello @KevinM1 ,

There are many ways, it all depends what kind of authentication you seek (token only, basic auth, oauth, etc)

If you elaborate, maybe we can help and/or direct you to a place where you can find that kind of information.

Cheers

indeed there are many ways to do it and as this is handled via the SecurityBundle its beyond the scope of this Bundle.

btw I am open to adding a small section to the docs to point people at resources explaining different REST related auth strategies

To be honest, I'm not sure which way this project will go re: authentication. First my boss mentioned OAuth, then classic username/password, then just a token. So he still seems a bit confused.

So I guess there's nothing to see here.

That said, +1 for the docs pointing at different REST related authentication strategies.

@KevinM1 well with the SecurityBundle you could support all of them at the same time :) Now it's actually fair easy for your boss to choose from. IMHO if you create a wide open api for the public to use, I would go for the oauth authentication. If not it could be much faster to implement a token or user/password through e.g basic auth. For example I maintain an api used by a couple of customers only and opted for a token + basic auth (token = needed to use the api, basic auth = user/password from the underlying application)

An other case could be to use WSSE which is very well explained here: http://symfony.com/doc/2.3/cookbook/security/custom_authentication_provider.html#meet-wsse

Have fun :)

I could preprare a cookbook on integration oauth2 with for rest bundle if anyone would be interested.

@defrag That could be very interesting :) I could also help on doing one for basic authentication and token.

@lsmith77 what do you think?

sounds very interesting. Is there a general cookbook for normal
authentication too? (as described above with security bundle)

This is as simple as integrating FOSOAuthServerBundle tho :)

Okay, I finally got the specs from my boss:

He wants it so that when a person registers their account, it creates an API key that's linked to their account and will be stored on the client. That key will then be used whenever a user does something potentially dangerous, like submitting an order, modifying their credentials, etc.*

So, I basically have to use a token, but only with a certain handful of routes. Safe requests (like simply using GET to obtain a list of items) won't require the key/token.

*Note that I'm not convinced of the security of this method, but, well, I'm not in charge. :-/

So, I've looked over the cookbook entry for API key authentication, but I'm unsure of what, if any, of that I should use given I'm using both FOSRest and FOSUser. Specifically, I'm not sure how to use the FOSUserBundle as the user provider in this case.

@KevinM1 yes you can use this bundle https://github.com/uecode/api-key-bundle

good luck

I am using traditional username/password authentication, but using custom headers.

I use this function in my controller to validate users.
*Note that I pass $this is passed as $context

    private function currentUser($context){
        $username = @$context->container->get('request')->headers->get("key");
        $password = @$context->container->get('request')->headers->get("secret");
        return $this->container->get('helper')->loginUser($username, $password);
    }

And I have this registered as a service

public function loginUser($username, $password){

        $securityContext = $this->container->get('security.context');
        if ($securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
            return $securityContext->getToken()->getUser();
        }

        /* Validate the User */
        $user_manager = $this->container->get('fos_user.user_manager');
        $factory = $this->container->get('security.encoder_factory');
        $user = $user_manager->loadUserByUsername($username);
        $encoder = $factory->getEncoder($user);
        $validated = $encoder->isPasswordValid($user->getPassword(),$password,$user->getSalt());
        if (!$validated) {
            http_response_code(400);
            echo "Validation Failed";
            exit;
        } else {
            $token = new UsernamePasswordToken($user, null, "main", $user->getRoles());
            $this->container->get("security.context")->setToken($token); //now the user is logged in

            //now dispatch the login event
            $request = $this->container->get("request");
            $event = new InteractiveLoginEvent($request, $token);
            $this->container->get("event_dispatcher")->dispatch("security.interactive_login", $event);

            return $user;
        }
    }

It is tested and working using both browser based and CURL based methods.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

soullivaneuh picture soullivaneuh  路  5Comments

pathmissing picture pathmissing  路  4Comments

oliver13 picture oliver13  路  3Comments

marcoshoya picture marcoshoya  路  7Comments

MaksSlesarenko picture MaksSlesarenko  路  4Comments