jameswagoner's avatar

API Authorization via Public and Secret Keys

I can't seem to find what I am looking for either cause I am don't have the right search criteria or everything is focused on username / password authentication. I think it is both to be honest.

What I am after is for users to have a secret and public key like you would find with other APIs offering a service (Stripe, PayPal, UPS, etc).

Is it really as simple as generating a key for a user then check if it is valid with every request? Valid being whatever my requirements are? Feel like it should be more complicated than that.

0 likes
3 replies
jameswagoner's avatar
jameswagoner
OP
Best Answer
Level 3

So after scouring projects on GitHub and other sources, I found that it is a simple check to match up keys. I have only implemented a secrete key (meant to be used server side) via a custom auth method with Dingo API.

Below is my implementation with Dingo API. Just add in the class to your API config.

namespace App\Providers\Guard;

use Dingo\Api\Auth\Provider\Authorization;
use Dingo\Api\Routing\Route;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

class GuardProvider extends Authorization
{
    /**
     * Get the providers authorization method.
     *
     * @return string
     */
    public function getAuthorizationMethod()
    {
        return 'X-Authorization';
    }

    /**
     * Authenticate the request and return the authenticated user instance.
     *
     * @param \Illuminate\Http\Request $request
     * @param \Dingo\Api\Routing\Route $route
     *
     * @return mixed
     */
    public function authenticate(Request $request, Route $route)
    {
        $key = $request->header(env('API_AUTH_HEADER', 'X-Authorization'));
        if (empty($key)) $key = $request->input(env('API_AUTH_HEADER', 'X-Authorization'));
        if (empty($key)) throw new UnauthorizedHttpException('Guard', 'The supplied API KEY is missing or an invalid authorization header was sent');

        $user = app('db')->select("SELECT * FROM users WHERE users.key = ?", [$key]);
        if (!$user) throw new UnauthorizedHttpException('Guard', 'The supplied API KEY is not valid');

        return $user;
    }
}

As I mentioned in the OP, feels like this isn't secure at all. However, when you get down to the nuts and bolts of other solutions, it is nearly the same.

ZetecVan's avatar

I didn't see your OP, otherwise I would have pointed you in the direction of Phil Sturgeons book 'Build APIs You Won't Hate' https://leanpub.com/build-apis-you-wont-hate

You are implementing the OAuth 2.0 "Access token" method there. Some quotes from the book:

You should always try to use the Authorization header to send your tokens whenever possible. The query-string is secured when using SSL, but unless they are intentionally blocked then access tokens could start turning up in server logs and various other places. Also, browsers will store the full URL (including query-string) in history. This could easily compromise the integrity of users security if their computer is stolen or if a sibling decides to play a prank.

OAuth 2.0’s access tokens will (can) expire after an arbitrary period of time, defined by the OAuth server. When you request an access token you will usually be provided with a “Refresh Token” and an expiry offset, which is the number of seconds until the token expires. Some servers send you a unix time at which it expires. Folks like to do things different for some reason, but if you know what to look out for it is not so bad.

Please or to participate in this conversation.