flask-restplus-server-example icon indicating copy to clipboard operation
flask-restplus-server-example copied to clipboard

auth failed with access_token from Client Credentials Grant

Open taoweibang opened this issue 5 years ago • 3 comments

$ curl 'http://127.0.0.1:5000/auth/oauth2/token?grant_type=client_credentials' --user 'documentation:KQ()SWK)SQK)QWSKQW(SKQ)S(QWSQW(SJ*HQ&HQW*SQ*^SSQWSGQSG'
{"access_token": "lYoijoYaTgXZi1bLQTs4PuItKsNHNY", "token_type": "Bearer", "expires_in": 3600, "scope": "users:write teams:write auth:write users:read auth:read teams:read"}

Grab the above access_token and access protected resources.

$ curl --header 'Authorization: Bearer lYoijoYaTgXZi1bLQTs4PuItKsNHNY' 'http://127.0.0.1:5000/api/v1/users/me'
{
    "status": 401, 
    "message": "The server could not verify that you are authorized to access the URL requested. You either supplied the wrong credentials (e.g. a bad password), or your browser doesn't understand how to supply the credentials required."
}

taoweibang avatar Apr 09 '19 15:04 taoweibang

I confirm the issue. I will dive into it later this week.

frol avatar Apr 09 '19 16:04 frol

Ah, I see now. The documentation misguided the use of Client Credentials Grant. The documentation "user" is not an active user, it serves the "application" user role (e.g. a third-party Twitter service needs its own application key/secret [in my example, you can create an inactive user with username/password and issue client id/secret for the service] to authenticate real users). Thus, you need to issue OAuth2 client id/secret for an active user; you can do this either via direct access to the database or via REST endpoints:

Authenticate as a target user using Resource Owner Password Credentials Grant (or in any other way):

$ curl -X POST --user 'documentation:' -F 'username=root' -F 'password=q' 'http://127.0.0.1:5000/auth/oauth2/token?grant_type=password'
{"access_token": "zrib5LuDmOQ0DmFd73SN37tll6eJvG", "expires_in": 3600, "token_type": "Bearer", "scope": "users:write teams:write auth:write users:read auth:read teams:read", "refresh_token": "gG2yfwaou6c1eUqaZRSSZjQPVboyTn"}

(optional) Test the access_token:

$ curl --header 'Authorization: Bearer zrib5LuDmOQ0DmFd73SN37tll6eJvG' 'http://127.0.0.1:5000/api/v1/users/me'
{
    "is_active": true,
    "last_name": "",
    "email": "root@localhost",
    "username": "root",
    "updated": "2017-03-07T15:05:49.574463+00:00",
    "middle_name": "",
    "is_admin": true,
    "is_regular_user": true,
    "created": "2017-03-07T15:05:49.574439+00:00",
    "first_name": "",
    "id": 1
}

Issue OAuth2 client id and secret:

$ curl -X POST --header 'Authorization: Bearer zrib5LuDmOQ0DmFd73SN37tll6eJvG' -F 'default_scopes=users:read' 'http://127.0.0.1:5000/api/v1/auth/oauth2_clients/'
{
    "user_id": 1,
    "client_type": "public",
    "client_id": "p2LqTKz6BdB7u4luBssLL5smc8jvtGGB6Fcm5Sli",
    "default_scopes": [
        "users:read"
    ],
    "redirect_uris": [],
    "client_secret": "eWslBvJVQMqTLRxlOCDyM7Umv4bp2OqL7kZZILF4QJAEmJiSle"
}

Issue the access_token using Client Credentials Grant:

$ curl 'http://127.0.0.1:5000/auth/oauth2/token?grant_type=client_credentials' --user 'p2LqTKz6BdB7u4luBssLL5smc8jvtGGB6Fcm5Sli:eWslBvJVQMqTLRxlOCDyM7Umv4bp2OqL7kZZILF4QJAEmJiSle'
{"access_token": "76Z4u3EWQIRpoU5vCkOs8Bw2mfJ4Be", "expires_in": 3600, "token_type": "Bearer", "scope": "users:read"}

Test the access_token issued with Client Credentials Grant:

$ curl --header 'Authorization: Bearer 76Z4u3EWQIRpoU5vCkOs8Bw2mfJ4Be' 'http://127.0.0.1:5000/api/v1/users/me'
{
    "is_active": true,
    "last_name": "",
    "email": "root@localhost",
    "username": "root",
    "updated": "2017-03-07T15:05:49.574463+00:00",
    "middle_name": "",
    "is_admin": true,
    "is_regular_user": true,
    "created": "2017-03-07T15:05:49.574439+00:00",
    "first_name": "",
    "id": 1
}

frol avatar Apr 11 '19 09:04 frol

I will need to clarify the documentation and consider a better error message.

frol avatar Apr 11 '19 09:04 frol