colymba/silverstripe-restfulapi

Trouble with setting up token authentication

Closed this issue · 8 comments

Hello there, first off I want to thank you so much for creating this great silverstripe addon. I'm quite new to silverstripe (only on my second or third week using it) but I had no issue setting up the basic api with basic permissions. Very well done. Next I just to ask you some questions to help me get the token authentication setup in the way I need it. Please forgive me for anything simple that I might not understand, this is the first RESTful API I have setup with tokens so I'm a bit of a newbie. On to the questions:

  1. How do I setup the basic token authentication? I have read through your docs on it and placed this configuration code into my config.yml:
RESTfulAPI:  
  authentication_policy: true
  dependencies:
    authenticator: '%$RESTfulAPI_TokenAuthenticator'
ApiUser:
  extensions:
    - RESTfulAPI_TokenAuthExtension
RESTfulAPI_TokenAuthenticator:
  tokenOwnerClass: 'ApiUser'

and used the api/auth/login?email=*my-email*&pwd=*my-pass* url (which just returns []).

  1. I have seen some users (in issue posts) apply the
extensions:
    - RESTfulAPI_TokenAuthExtension

code to the Members model instead of the ApiUser model. What is the benefits of applying it to ApiUser?

3.For the site I am creating we would like to have a system similar to google+/facebook/twitter where the user goes into there settings screen(or in our case into the CMS) to create a API token. This token would then be used by our users in their applications,websites, or apps to to connect and retrieve data through our API. Is this possible to create with your addon? If so could you perhaps give me some code to get me started.And if it is not possible with your addon could you recommend to me another addon that might suite my needs?

Thank you in advance,
Mooror

UPDATE 1: So I did some more research and found that I had miss-read some of the docs. I had not realized that this snippet:

RESTfulAPI_TokenAuthenticator:
    tokenOwnerClass: 'Member'

needed to be indented under the RESTfulAPI settings. Once I realized this I corrected my code (naturally) in the config.yml and rebuilt/flushed my install. After I did this I once again tried accessing the api/auth/login?email=*my-email*&pwd=*my-pass* url. This time I did not receive the empty json object but instead something like this:

{"result":true,"message":"Logged in.","code":0,"token":"5f7f32cc1d8b89c3efed2e3fohqWf5B0aGBPEUw59m5N9O7cjgcCC","expire":1456395040,"userID":1}

Of course, if this was not a localhost environment I would never post my tokens anywhere online, but in this case I am indeed on a localhost :D. Any way, This I though would be the end to my problems as I thought I could use this new token in the url with ?X-Silverstripe-Apitoken=XX like you suggested in this post #28. However even when adding my newly generated token I still got the error:

{"message":"Token invalid.","code":2}

So Ill keep working on solving this, but any help you can provide will be wonderful.

Thanks again,
Mooror

@mooror just some quick questions. Do you have a class ApiUser? This was in the doc as an example name if the authenticator was used with something else that a Member class.

Then, the token itself, is usually passed in a request header named X-Silverstripe-Apitoken, but if you cannot modify the headers send to the server, you can pass it as a query var, which seem to be your case, in that case, your query URL would look like api/Object?token=XXXXXXXX.

Thos default X-Silverstripe-Apitoken and ?token are in the doc here https://github.com/colymba/silverstripe-restfulapi/blob/master/doc/TokenAuthenticator.md and can be changed via config if needed.

let me know how it goes

Thank you colymba for your reply.
After adding the

extensions:
    - RESTfulAPI_TokenAuthExtension

code to the Member model instead of the ApiUser model and changing the tokenOwnerClass to Member (which I believe is the default) I was successfully able to retrieve a single record from my Package model with this url: localhost/silver/silver/api/package/5?token=df7ea9f738ee6902b745duQtPvSv6mGl9caWiaFQMf6cgHCkbzIsC.

However when trying to retrieve multiple records (with http://localhost/silver/silver/api/package?name=test&token=df7ea9f738ee6902b745duQtPvSv6mGl9caWiaFQMf6cgHCkbzIsC I get this error:

[User Error] Uncaught SS_DatabaseException: Couldn't run query: SELECT DISTINCT "Package"."ClassName", "Package"."LastEdited", "Package"."Created", "Package"."Name", "Package"."Description", "Package"."Price", "Package"."Maintainers", "Package"."PublishDate", "Package"."RepositoryLink", "Package"."Version", "Package"."Default", "Package"."ModeID", "Package"."TypeID", "Package"."CategoryID", "Package"."ThumbnailID", "Package"."ID", CASE WHEN "Package"."ClassName" IS NOT NULL THEN "Package"."ClassName" ELSE 'Package' END AS "RecordClassName" FROM "Package" WHERE ("name" = ?) AND ("token" = ?) LIMIT 100 Unknown column 'token' in 'where clause'

I double checked the database to confirm that I have a Package record with the name of test and found that I indeed did. So I tried disabling the authentication_policy and returning to the above url minus the token and it worked just fine. I even tried http://localhost/silver/silver/api/package?name=test?token=df7ea9f738ee6902b745duQtPvSv6mGl9caWiaFQMf6cgHCkbzIsC
(which has a ? before the token instead of &) but this returned:

{"message":"Token invalid.","code":2}

Reversing the order of the token and name perimeters also make no difference. I'm not sure if this is a bug with passing tokens in through the url rather then the header.Or if I am just being a noob and passing it in wrong.

Thanks in advance,
Mooror
P.S. I realize that the api engine/script is using the token perimeter in the database query.

Also, how simple would it be to create a field in the CMS user profile page which would allow users to create an api token (and view there current one if they have already created one)

Thanks in advance,
Mooror

Thinking on it more, I thought that it was most likely if this was an issue with just the passing the token in with search parameters in url, then passing the token in the (X-Silverstripe-Apitoken) header instead should work just fine. Sure enough when I used Chrome's Postman and sent a Get request to `http://localhost/silver/silver/api/package?name=test (with my api in the header) it worked just fine.In my case I have the ability to add my API token to the header in my Server side 'app', however I am not sure if everyone else does. So this still might be a bug that needs fixing.

Thanks in advance,
Mooror

@mooror like you found, your error is due to the token query parameter.

And it is somewhat of a bug, more like something that should be in the default config...

Basically the QueryHandler parses the query parameters as column filter, and so thinks token is one of those.

This can easily be avoided by adding token to the skipedQueryParameters config of the RESTfulAPI_DefaultQueryHandler, see here: https://github.com/colymba/silverstripe-restfulapi/blob/master/doc/DefaultQueryHandler.md

So for now, if you are still using the token query parameters, you could add this to your yaml config:

RESTfulAPI_DefaultQueryHandler:
  skipedQueryParameters:
    - 'TOKEN'

Sorry I forgot about this earlier, and yes this should be added to the default config.

To get the API token to show up in the CMS you could just create a new DataExtension and add it to your Member. There in the updateCMSFields you should be able to add again the token and life fields. These fields are removed by default by the RESTfulAPI_TokenAuthExtension, see here https://github.com/colymba/silverstripe-restfulapi/blob/master/code/authenticator/RESTfulAPI_TokenAuthExtension.php#L24

Hope this helps

@colymba I'm having similar issues. Any help would be great :)

I have:

MyMember:
has_many: MyObject

MyObject
has_one: MyMember

coolness!...

I've got it so mysite/api/MyObject/123?token=123 and mysite/api/MyObject?token=123 work but I only want the member to be able to access/view/edit MyObjects they own and not other MyMembers.

Maybe you can point me it the right direction?

Cheers heaps

@nimeso this isn't really related to token authentication. You need to look into api_access_control, see https://github.com/colymba/silverstripe-restfulapi/blob/master/doc/RESTfulAPI.md

This thread is about what you are trying to achieve: #49