stevenmaguire / oauth2-keycloak

Keycloak Provider for OAuth 2.0 Client
MIT License
208 stars 151 forks source link

Bearer-Only Client #22

Open trickert76 opened 4 years ago

trickert76 commented 4 years ago

I wan't to use this library to secure my PHP backend with a Bearer-Token. Any Request needs to have a header: Authentication: Bearer . I'm able to extract that token already from the request and want to send it to the provider to verify it.

  if (preg_match("/Bearer\s+(.*)$/i", $request->getHeaderLine("Authorization"), $matches)) {
    $token = $matches[1];
    ...

My Keycloak Realm is configured with realm myrealm and it has a clientId backend which is defined as bearer-only.

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
    'authServerUrl'         => 'https://keycloak-server/auth',
    'realm'                 => 'myrealm',
    'clientId'              => 'backend',
    'clientSecret'          => 'mysecret'
]);

$accessToken = $provider->getAccessToken('authorization_code', ['code' => $token]);
error_log(print_r($accessToken,true));

With curl I call https://keycloak-server/auth/realms/$REALM/protocol/openid-connect/token as another client (frontend) to create a token, then I call my PHP script with that token.

But in getAccessToken, I'm getting an error with

invalid_client: Bearer-only not allowed

The trace is:

/vendor/stevenmaguire/oauth2-keycloak/src/Provider/Keycloak.php","line":192,"trace":"
#0 /vendor/league/oauth2-client/src/Provider/AbstractProvider.php(613): Stevenmaguire\\OAuth2\\Client\\Provider\\Keycloak->checkResponse(Object(GuzzleHttp\\Psr7\\Response), Array)
#1 /vendor/league/oauth2-client/src/Provider/AbstractProvider.php(528): League\\OAuth2\\Client\\Provider\\AbstractProvider->getParsedResponse(Object(GuzzleHttp\\Psr7\\Request))\n
#2 /src/public/v1/libs/OAuthAuthentication.class.php(166): League\\OAuth2\\Client\\Provider\\AbstractProvider->getAccessToken(Object(League\\OAuth2\\Client\\Grant\\AuthorizationCode), Array)

I'm not sure, if this is a Keycloak issue - but a SpringBoot-REST-Controller is working with that clientId. If I change the client to "confidential", that I'm getting a different error.

invalid_grant: Code not valid

Even when it works - the PHP service should be a REST backend without user interaction and in that case the Bearer Token seems to be right to me. What do I miss?

0xch commented 4 years ago

Hi, I guess it might be a problem with Keycloak configuration. Please check if you have set "public" in "Access Type" option in Keycloak console on "Clients->{chosen client}->Settings (tab)"

trickert76 commented 4 years ago

I could do that - but in that case, the client isn't a Backend service anymore. Public clients are frontends that cannot trust there runtime - like Angular running in users Browser environment.

Then it is public and based on the protocol the client without a token should be redirected to SSO login page of the OIDC provider. And because we talk about a backend REST service, this isn't an option, because all "requests" should only response with a valid REST response. Redirecting a non-interactive client to a interactive website isn't an option.

As I wrote - it works with bearer-only/confidential settings when I use a SpringBoot-Keycloak-Adapter. So I'm sure now, this isn't a Keycloak settings issue. Also I was able to integrate a JWT authentication in my PHP backend (because Bearer Token is a JWT Token with a signature from the OIDC provider). That works for me, but it would be easier with a complete integration (KID, reading well-known infos from OIDC provider).....