How to implement authentication on a REST architecture with Parse?

Hello, I am currently redoing a legacy web application that uses the PHP Parse SDK, and I am in the login authentication part. In the old application, we used $ _SESSION and ParseToken when doing ParseUser::signIn() and ParseUser::currentUser() to check if you have a session with a valid token, however the new application is being made using the REST architecture, where one of the REST concepts is that the server must not keep state, that is, be stateless, and in that case it would be the client that would have to send the necessary data.

When searching the internet and forums, I saw that it is common for developers to authenticate with JWT, where the client would make a request for a server’s route and the server would return a token, and through that token authentication would take place.

I even implemented something using Firebase / jwt-php, where the client [Postman] makes a request for the route /login sending via body [username, password] and in case of success, returns the token to be used in secure route requests.

NOTE: Code is as simple as possible, without validation and cleaning just to show the example.

Action /login


$username = $request->getParsedBody()['username'];
$password = $request->getParsedBody()['password'];

$userAuthenticated = ParseUser::logIn($username, $password);

$payload = [
    'data' => $userAuthenticated,
    'exp'  => time() + 3600
];

$token = JWT::encode($payload, $_ENV['JWT_SECRET_KEY']);

echo json_encode(['token' => $token]);

And the protected routes have a middleware that checks if the time has expired, and if this has happened, an exception with a 401 code is launched.

So far so good, authentication works, the problem I don’t know if it’s right to do it this way, since I need to give a ParseUser::logIn(), just to generate a session in the database and I don’t even use it this session to do some authentication, with the exception of operations in the bank, because from what I saw in the documentation, if there is no valid session in the database, the application will return invalid session token error and also when making the request for another route ParseUser::currentUser() returns null, and this may be a problem in the future.

Does anyone have any idea how I can implement authentication for a REST application made in PHP? I appreciate the help !!

I believe the easiest way would be just replacing the default session storage (which uses $_SESSION) to something else that stores the session in, for example, Redis. Reference: PHP Developers Guide | Parse

But the way you are doing should also work. You will only have to make sure that, every time that a request comes, you will decode the JWT, get the Parse Session token from there, and use ParseUser::become to set the current user: PHP Developers Guide | Parse

1 Like

Thank you for the answer, and it gave me a light.

I put a middleware to get the decoded token from jwt and used it on ParseUser :: become () looking like this.

// Middleware

BecomeTokenParseMiddleware implements MiddlewareInterface
{

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {

        $jwtPayloadDecoded = $request->getAttribute('token'); // Token generated by JWT decoded
        
        $token = $jwtPayloadDecoded['data']->_sessionToken;  // Token generated by `ParseUser :: signIn ()`
        
        ParseUser::become($token);

        return $handle->handler($request); // go to next middleware stack
    }
}

And with that I can guarantee that the user’s session token authenticated and saved in the Session class in Parse is valid and I can also perform CRUD operations.

Now a question, I got the same result [Perform CRUD operations] without the need to do ParseUser::become(), with the exception that I would not be able to validate if the saved sessionToken generated by the ParseUser::signIn method in the JWT payload and returned later in the request, it is valid and if it exists in the Session class of Parse.

So the idea behind ParseUser::become, according to the documentation, is just to validate that this token passing to the ParseUser::become($token) method is valid? Are there any other restrictions that would not allow me to perform operations on the database without a valid sessionToken?

And another question, I believe that this is not directly linked to the question of the post, and if necessary I will create another post, does the use of masterKey turn off this explicit security behavior from this code below?

$query = ParseUser::query();

$userAgain = $query->get($user->getObjectId());

$userAgain->set("username", "another_username");`

// This will throw a ParseException, since the ParseUser is not authenticated
$userAgain->save();

Because I did a test here with this code, but as I said up there, without the need for ParseUser::become() and it worked normally.

Note: I also did the test without ParseUser::become() and without ParseUser::signIn(), that is, without being authenticated and with a valid session, however the documentation says that this would return an exception, only that there, he is not using MasterKey, so I had this doubt.

$query = ParseUser::query();

$user = $query->get('9DSikPodk4'); // User existing in database classe _User

$user->set('username', $post['phone']);

$user->set('password', '12345');

var_dump(ParseUser::getCurrentUser()); // Return null, because I am not authenticated

$user->save(true); // Saved user with success and using masterKey

Probably your CLP setup for the User class is too open (and that’s dangerous). You should setup CLP/ACL in such a way that only authorized users have access to read/write the data. See more info here: JavaScript Developers Guide | Parse

1 Like