[keycloak-dev] OTP API

Thomas Darimont thomas.darimont at googlemail.com
Fri Nov 11 09:06:46 EST 2016


Hello Marek,

I'm already using the direct grant auth flow for authenticating a desktop
app against the Keycloak userbase,
but thanks for the hint with the totp parameter, for the record I added a
simple curl example below.

Does anyone know about OIDC providers that support the display=popup
parameter - I could not find a
project / product that supports this.

Btw. the usage for OTP to verify sensitive operations or transaction
authorization seems indeed to be quite common.
http://www.transmitsecurity.com/use_case/otp-one-time-password/
https://bankapi.net/docs/public/authorization-getstarted.html
https://www.owasp.org/index.php/Transaction_Authorization_Cheat_Sheet

Cheers,
Thomas

--

KC_REALM=otp-validation-test
KC_USERNAME=tester
KC_PASSWORD=test
KC_OTP_CODE=654328
KC_CLIENT=test-client
KC_CLIENT_SECRET=c57dc179-09bb-4bb7-9128-91b29dd7fc35
KC_URL="http://localhost:8081/auth"

## Request Tokens for credentials
KC_RESPONSE=$( \
   curl -v \
        -d "username=$KC_USERNAME" \
        -d "password=$KC_PASSWORD" \
        -d 'grant_type=password' \
        -d "client_id=$KC_CLIENT" \
        -d "client_secret=$KC_CLIENT_SECRET" \
        -d "totp=$KC_OTP_CODE" \
        "$KC_URL/realms/$KC_REALM/protocol/openid-connect/token" \
    | jq .
)

KC_ACCESS_TOKEN=$(echo $KC_RESPONSE| jq -r .access_token)
KC_ID_TOKEN=$(echo $KC_RESPONSE| jq -r .id_token)
KC_REFRESH_TOKEN=$(echo $KC_RESPONSE| jq -r .refresh_token)

## Validate otp token with custom credential validation endpoint

KC_OTP_CODE=027253 curl -v \
     -H "Authorization: Bearer $KC_ACCESS_TOKEN" \
     -H "Content-Type: application/json" \
     -d "[{"\""type"\"":"\""totp"\"","\""value"\"":"\""$KC_OTP_CODE"\""}]" \
     $KC_URL/realms/$KC_REALM/credential-validation


2016-11-11 11:26 GMT+01:00 Marek Posolda <mposolda at redhat.com>:

> On 11/11/16 11:00, Thomas Darimont wrote:
>
>> Hi Stian,
>>
>> thanks for the feedback.I understand the philosophy behind not exposing
>> credentials to an application and agree that
>> one way to solve this is by using a custom endpoint.
>>
>> Question: Is there a general recommendation or guideline about resource
>> names / paths? E.g. something like custom resources should be located
>> beneath a special base path (e.g. /custom) to avoid potential clashes with
>> Keycloak resources in newer versions?
>>
>> I also like the idea for (partial) re-auth via some sort of popup /
>> iframe.
>> Are there any JIRAs logged for this already?
>> Another thing is that this might not work in every case, e.g. when
>> integrating Desktop applications where a
>> the "client" sends the user credentials to a server which then needs to
>> check those credentials against keycloak, e.g. by trying to acquire an
>> access token.
>>
> One related JIRA is the support for OIDC "display" parameter. This allows
> to open login page in the popup (among other things). See
> https://issues.jboss.org/browse/KEYCLOAK-3322 .
>
> Regarding desktop client, we already have "Direct Grant" authentication
> flow, which has some support for OTP verification. You just need to add
> "totp" parameter to the request though. See the ValidateOTP class for
> details.
>
> Marek
>
>
>> Cheers,
>> Thomas
>>
>> 2016-11-11 8:48 GMT+01:00 Stian Thorgersen <sthorger at redhat.com>:
>>
>> This is not something we should add IMO. As Bill points out the whole idea
>>> is to not expose credentials to application. I'd rather see something
>>> that
>>> works without exposing credentials to the users. Could do a redirect with
>>> re-auth required. Could require just adding otp on re-auth. Could
>>> possibly
>>> do a popup with embedded login from KC. I'm sure there's cleaner ways
>>> than
>>> the applicaiton collection OTP.
>>>
>>> However, it's perfectly possible to implement this using a custom rest
>>> resource so if you really want it to do this then do it that way.
>>>
>>> On 10 November 2016 at 21:55, Thomas Darimont
>>> <thomas.darimont at googlemail.
>>> com> wrote:
>>>
>>> Hello guys,
>>>>
>>>> I agree with you Bill that requiring a user to re-auth by redirecting to
>>>> the
>>>> auth-server is often the best thing to do.
>>>> However in business applications one often sees the requirement to
>>>> periodically
>>>> reauthenticate the user without requiring the user to login again (e.g.
>>>> without leaving the application).
>>>> A common example for this is that users need to reenter a OTP credential
>>>> before performing a certain critical operation...
>>>>
>>>> I gave this a quick spin...
>>>> https://github.com/thomasdarimont/keycloak/commit/e891ca604a
>>>> cf5fd494525092c7a88628d9fb20bd
>>>> as you can see I took some inspiration from the userinfo endpoint.
>>>>
>>>> Works quite well so far, but bruteforce protection is still missing.
>>>>
>>>> A demo session via curl looks like this:
>>>>
>>>> $ KC_REALM=otp-validation-test
>>>> KC_USERNAME=tester
>>>> KC_PASSWORD=test
>>>> KC_CLIENT=test-client
>>>> KC_CLIENT_SECRET=c57dc179-09bb-4bb7-9128-91b29dd7fc35
>>>> KC_URL="http://localhost:8081/auth"
>>>>
>>>> ## Request Tokens for credentials
>>>> KC_RESPONSE=$( \
>>>>     curl -v \
>>>>          -d "username=$KC_USERNAME" \
>>>>          -d "password=$KC_PASSWORD" \
>>>>          -d 'grant_type=password' \
>>>>          -d "client_id=$KC_CLIENT" \
>>>>          -d "client_secret=$KC_CLIENT_SECRET" \
>>>>          "$KC_URL/realms/$KC_REALM/protocol/openid-connect/token" \
>>>>      | jq .
>>>> )
>>>>
>>>> KC_ACCESS_TOKEN=$(echo $KC_RESPONSE| jq -r .access_token)
>>>> KC_ID_TOKEN=$(echo $KC_RESPONSE| jq -r .id_token)
>>>> KC_REFRESH_TOKEN=$(echo $KC_RESPONSE| jq -r .refresh_token)
>>>> *   Trying 127.0.0.1...
>>>>    % Total    % Received % Xferd  Average Speed   Time    Time     Time
>>>>   Current
>>>>                                   Dload  Upload   Total   Spent    Left
>>>>   Speed
>>>>    0     0    0     0    0     0      0      0 --:--:-- --:--:--
>>>> --:--:--
>>>>    0* Connected to localhost (127.0.0.1) port 8081 (#0)
>>>>
>>>>> POST /auth/realms/otp-validation-test/protocol/openid-connect/token
>>>>>
>>>> HTTP/1.1
>>>>
>>>>> Host: localhost:8081
>>>>> User-Agent: curl/7.45.0
>>>>> Accept: */*
>>>>> Content-Length: 122
>>>>> Content-Type: application/x-www-form-urlencoded
>>>>>
>>>>> } [122 bytes data]
>>>> * upload completely sent off: 122 out of 122 bytes
>>>> < HTTP/1.1 200 OK
>>>> < Connection: keep-alive
>>>> < Content-Type: application/json
>>>> < Content-Length: 3713
>>>> < Date: Thu, 10 Nov 2016 20:32:16 GMT
>>>> <
>>>> { [3713 bytes data]
>>>>
>>>> # We got an acces token ... now lets try to validate a wrong OTP code
>>>>
>>>> curl -v \
>>>>       -H "Authorization: Bearer $KC_ACCESS_TOKEN" \
>>>>       -H "Content-Type: application/json" \
>>>>       -d '[{"type":"totp", "value":"24861"}]' \
>>>>       $KC_URL/realms/$KC_REALM/credential-validation
>>>> *   Trying 127.0.0.1...
>>>> * Connected to localhost (127.0.0.1) port 8081 (#0)
>>>>
>>>>> POST /auth/realms/otp-validation-test/credential-validation HTTP/1.1
>>>>> Host: localhost:8081
>>>>> User-Agent: curl/7.45.0
>>>>> Accept: */*
>>>>> Authorization: Bearer eyJhb...EW3Q
>>>>> Content-Type: application/json
>>>>> Content-Length: 34
>>>>>
>>>>> * upload completely sent off: 34 out of 34 bytes
>>>> < HTTP/1.1 400 Bad Request
>>>> < Connection: keep-alive
>>>> < Content-Length: 0
>>>> < Date: Thu, 10 Nov 2016 20:30:42 GMT
>>>> <
>>>> * Connection #0 to host localhost left intact
>>>>
>>>> # Let's try a currently valid OTP code
>>>>
>>>>   curl -v \
>>>>       -H "Authorization: Bearer $KC_ACCESS_TOKEN" \
>>>>       -H "Content-Type: application/json" \
>>>>       -d '[{"type":"totp", "value":"949784"}]' \
>>>>       $KC_URL/realms/$KC_REALM/credential-validation
>>>> *   Trying 127.0.0.1...
>>>> * Connected to localhost (127.0.0.1) port 8081 (#0)
>>>>
>>>>> POST /auth/realms/otp-validation-test/credential-validation HTTP/1.1
>>>>> Host: localhost:8081
>>>>> User-Agent: curl/7.45.0
>>>>> Accept: */*
>>>>> Authorization: Bearer eyJhb...EW3Q
>>>>> Content-Type: application/json
>>>>> Content-Length: 35
>>>>>
>>>>> * upload completely sent off: 35 out of 35 bytes
>>>> < HTTP/1.1 200 OK
>>>> < Connection: keep-alive
>>>> < Content-Length: 0
>>>> < Date: Thu, 10 Nov 2016 20:34:11 GMT
>>>> <
>>>> * Connection #0 to host localhost left intact
>>>>
>>>> Cheers,
>>>> Thomas
>>>>
>>>> 2016-11-10 14:27 GMT+01:00 Bill Burke <bburke at redhat.com>:
>>>>
>>>> Should be generic and not specific to a credential type.  Should also
>>>>> hook into brute force detection.  IMO though, one of the reasons for
>>>>> SSO
>>>>> and keycloak is that the application does not gather credentials.  This
>>>>> is the job of the auth server.  IMO, we'd be better off with expiring
>>>>> the login at the client side, redirecting to auth server, auth server
>>>>> sees that the user session is 3 hours old, and requests OTP.
>>>>>
>>>>>
>>>>> On 11/10/16 7:52 AM, Thomas Darimont wrote:
>>>>>
>>>>>> Hello Rohith,
>>>>>>
>>>>>> not that I know of - we'd also like to have this functionality.
>>>>>>
>>>>>>
>>>>>> What would be the best place to add that? Perhaps this could be added
>>>>>>
>>>>> to
>>>>
>>>>> the UsersResource with a new
>>>>>> endpoint like "/users/{userId}/otp-validation" or a (new) dedicated
>>>>>> resource.
>>>>>>
>>>>>> A client could  then do a POST to that endpoint with the current
>>>>>>
>>>>> user's
>>>>
>>>>> access token and the entered OTP code.
>>>>>> Keycloak could then lookup and check the provided otp code.
>>>>>> If the code is corret, response could indicate that via status HTTP
>>>>>>
>>>>> 200
>>>>
>>>>> or
>>>>>
>>>>>> HTTP 400 otherwise.
>>>>>>
>>>>>> Cheers,
>>>>>> Thomas
>>>>>>
>>>>>> 2016-11-10 12:11 GMT+01:00 gambol <gambol99 at gmail.com>:
>>>>>>
>>>>>> Hiya
>>>>>>>
>>>>>>> Does the latest version of Keycloak provide any means of verifying a
>>>>>>>
>>>>>> user's
>>>>>
>>>>>> TOTP?. Our use-case at the moment, we have an application which once
>>>>>>>
>>>>>> the
>>>>
>>>>> user is authenticated we issue a token of sorts ... however, we wish
>>>>>>>
>>>>>> to
>>>>
>>>>> provide a popup that requests a user's TOPT every few hours which we
>>>>>>> "could" verify via service account ... I can't see any access at the
>>>>>>>
>>>>>> moment
>>>>>
>>>>>> via the rest api
>>>>>>>
>>>>>>> Rohith
>>>>>>> _______________________________________________
>>>>>>> keycloak-dev mailing list
>>>>>>> keycloak-dev at lists.jboss.org
>>>>>>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>>>>>>
>>>>>>> _______________________________________________
>>>>>> keycloak-dev mailing list
>>>>>> keycloak-dev at lists.jboss.org
>>>>>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>>>>>
>>>>> _______________________________________________
>>>>> keycloak-dev mailing list
>>>>> keycloak-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>>>>
>>>>> _______________________________________________
>>>> keycloak-dev mailing list
>>>> keycloak-dev at lists.jboss.org
>>>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>>>
>>>>
>>> _______________________________________________
>> keycloak-dev mailing list
>> keycloak-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>
>
>
>


More information about the keycloak-dev mailing list