whole day was trying to create a session entity for my intent with actions-on-google-nodejs. Unfortunately without any success.
I believe that the this library doesn't support entities in any way, which is a bit sad. Am I right?
During my research I found this amazing post which is explaining how to create and manage entities through API , however they are using nodejs-dialogflow
Was considering using both libraries actions-on-google-nodejs and nodejs-dialogflow, but than when I'm catching the intent with actions-on-google-nodejs the second library (nodejs-dialogflow) will not have idea about the content and etc.
After further research I found the API documentation for sessions.entityTypes The "Try this API" works amazing with Google OAuth 2.0, however don't know how to authorize my server (express.js) with Google OAuth 2.0. I tried with API key but all the time I'm getting the following error:
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
Any suggestions how I can create a session entity for my intent?
The reason why I'm trying to use session entity is because the entity will change every couple of days and don't want to update the entity in dialogflow. My idea is to store it in DB (firebase) and on intent will validate if it match any of the values.
Keep in mind that the Session Entity must be set to the values you want before it is expected to be matched in an Intent. You probably should do this right when your Action starts, in your case. So if you have your "Welcome" intent, and a "State Option" intent, where the "Option" entity is in the "State Option" intent, you should update "Option" in the "Welcome" intent. You can't do it in the "State Option" intent, because it needs to have matched the Entity already.
The two libraries do completely different things, and can work well together. You will need to get the session path from the original request body, which you can get from conv.request using the a-o-g library, and the entity path, which you'd have to set in some way.
The nodejs-dialogflow library is just a wrapper around the REST API that you've also found (actually, probably around the gRPC equivalent, but it doesn't matter). The big thing that it does, however, is the work that will convert the secret key that you get from the service account into an access token that you need to send with every request. If you're not familiar with Google's OAuth 2 implementation, this can make things a lot easier, although it is certainly possible to do this yourself.
Finally, while the idea is sound and will work, remember that this will take some time during an Intent and that the user is waiting for a reply. Since this data will update infrequently, and for everyone, you may wish to use a similar API to just change the Entity periodically. This process could be something you trigger out of a scheduled (cron) job and have a way to trigger it manually if you need to.
Related
I am designing api for mobile application.
I am not sure should I have one endpoint login which will return tokens & user profile
Or have two endpoints and after login call getProfile endpoint.
I saw that people mostly use second option but I don't see benefit of that approach?
Thinking in terms of the single-responsibility principle (which basically says "API methods should do one thing really well"), I'd suggest separating these into two separate things:
POST /login would set up a session and return the session ID to be used in subsequent requests.
GET /profile would return profile information provided a valid session ID is provided.
There are obvious benefits along the "happy path" for combining these, mainly the fact that after a login operation completes, you automatically provide the user with the data they most obviously would want next (who the user is). Why waste an extra API call to find it out, right?
If that's all your API will ever need to support, then there's no reason to separate these. But there are a couple cases I can think of for why you might want them separate:
What if an existing and already logged-in user wants to fetch the latest profile information? This means you must support GET /profile anyway (or have them POST /login again which is wasteful).
What if profile information is already cached and the POST /login API call is only happening to re-authenticate the user inside the app to complete an action? You'd be wasting bandwidth by sending data that's not needed.
Additionally, testing is usually a bit easier when you have each API method doing the one thing they imply they do (POST /login logs the user in, GET /profile fetches the current logged-in user's profile).
I have to create a middleware API which a functionality to check for a key present in my database. If the key exists then it should simply fetch it(GET method). If not, then the API should create the key and its value in the database and return that(POST method). So since we have 2 fundamentally different methods being combined in this API, is it correct to do so? What should be the best way to design such API?
Don't combine them.
Return zero results from your GET method if you the record doesn't exist. Then in the client, if you receive zero results, POST the needed information to another API endpoint.
Combining the two ideas into one will create a hard to understand system. Your system should be deterministic, i.e. you can always know the result of every call before you call it.
One way to look at your API is to forget about the underlying database, but think about how an API client uses it.
If an API client does a GET request, 2 things happen:
The existing record is returned
A new record is created and is returned
A client might not actually care if 1 or 2 happened. For the perspective of the client, it might look like the resource always existed (even if it was technically just created).
So as long as there's no extra information that must be sent along with a POST request, it might be fine to use a GET request for both cases.
I don't know about your situation, typically it is best to have your get and post seperated. Though, if your client thinks that it needs to create a record and then posts the data, i dont see the problem with returning the resource and a 409 for the resource already existing. Here is a similar question HTTP response code for POST when resource already exists
Then the client can handle the 409 differently or the same as a 200 depending on your needs.
I am currently developing a strategy for Dialogflow on https://passportjs.org.
From what I've learnt, Dialogflow doesn't authenticate users. So I'm thinking about making a strategy (for passportjs) that identify users from every plateform differently (analyse the originalRequest differently for each plateform).
For example, the Telegram originalRequest has this field:
originalRequest.data.message.from.id
The Telegram says this field is a:
"Unique identifier for this user or bot"
So I think it is safe to use it for authentication and identify every intent of my users fulfilled by my webhook.
I was wondering about the actions-on-google authentication and I found the field originalRequest.data.user.userId.
The documentation says:
"Users can reset this identifier, so don't store important user data keyed off this identifier, because once it's reset, that information is no longer accessible by the user."
So the only reason to not trust the userId is because it can be reset? At the end of the documentation it says:
User ID lifetime - User IDs are reset automatically after 30 days of inactivity or if users unlink their accounts on the device.
And:
"If a registered user's voice isn't recognized by the device or no registered voice exists, then a different ID is used that is unique for just that conversation."
How to differentiate users from one other? Can some IDs be recycled?
The best way to differentiate users from each other is to use the userId field, as you've determined. On the AoG platform, the userId is meant to be used somewhat like a web cookie can be used - if you see it again, you are assured that this is the same user that used it last time. But if you see a new one, you have to assume that you've never seen this user before, even if it means they deleted the cookie.
To be clear - most of the time, the UserId will remain the same and you can expect returning users to have the same ID. This won't be true in only three cases:
They have reset the ID for this Action. So they have deliberately chosen to start over.
They didn't use the Action for 30 days, in which case it makes sense to treat them as a brand new user anyway in most cases.
They were not recognized as a normal user of this device, so they are treated anonymously. (This is the equivalent of the clunky "Do not remember me on this machine" setting you see on websites, which forces a session cookie rather than a persistent cookie.)
The phrasing is poor in the documentation - I think it is meant to remind developers that the user is ultimately in charge of their privacy. And Google both forces you to do the same and adopt policies that do so.
IDs will not be recycled. In fact, they won't even be re-used between different Actions, even for the same Assistant account.
Summary: If you see the same UserId, you can trust it is the same user you saw before. If you see a new one, assume they are a new user.
If you want a more robust way to identify users, you might consider using Account Linking which puts you in control of the identifying token. But that has significant additional overhead.
Be careful when using other authentication methods - Google limits how you're allowed to use them as part of an Action, and expressly forbids them in some cases. See the General Policies for details.
Background
I'm having a trouble with the design and implementation of a REST service which publishes content that some users cannot view (medical information, you know, country's laws), I'm using a ABAC-like/RBAC system to protect them, but what causes me concern is that I may be violating the REST pattern. My services does the following process for each query:
The security middleware reads a token from a session that an app/webpage sends using authorization header or cookies.
ABAC/RBAC Rules are applied to know if user can access the resource.
After authorize the token, my service executes the query and filters the results, hiding content that requesting user cannot see (if needed. POST, PUT and DELETE operations are almost exempt from this step). The filter is done using ABAC/RBAC rules.
An operation report is stored in logs.
I already know that sessions violates REST pattern, but I can replace it using BASIC/DIGEST authorizations. My real question is the following:
Question
Does hiding resources from list/retrieve operations violates REST pattern? As far I know, REST is stateless, so ... What happens if I use some context variables to filter my results (user id)? Am I violating REST? Not at all?
If I do, What are your recommendations? How can I implement this without breaking REST conventions?
First of all, client-side sessions don't violate REST at all. REST says the communication between client and server must be stateless, or in other words, the server should not require any information not available in the request itself to respond it properly. If the client keeps a session and sends all information needed on every request, it's fine.
As to your question, there's nothing wrong with changing the response based on the authenticated user. REST is an architectural style that attempts to apply the successful design decisions behind the web itself to software development. When you log in to Stack Overflow, what you see as your profile is different from what I see, even though we are both using the same URI, right? That's how REST is supposed to work.
I'd recommend returning status codes 401 (Unauthorized) if the user is not authorized to access a resource. And 404 (Not found) if you cannot confirm that the resource even exists.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4
A GET is meant to return a representation of the resource. Nowhere does it say that you must return everything you know about that resource.
Exactly what representation is returned will depend on the request headers. For example of you might return either JSON or XML depending on what the client requested. Extending this line of thinking; it is ok to return different representations of a resource based on the client's authentication without violating REST principals.
There are many excellent questions (and answers) on S.O. around the subject of REST and security. Many say "purists won't like this, but blah blah"... and then others says "you should never do that, because blah blah".
But I have not seen the solution that the "purists" are suggesting for the following scenario. So my question is - what are the "pure RESTful solutions" to the following scenario?
The simple scenario...
Imagine building a database/website that lets a user manage their favorite recipes. The website exposes a RESTful API so that users can query and manipulate their list from a custom program that they want to write (that utilizes this API).
So, user "A" has 3 favorite recipes with the ID's "1", "2" and "3".
User "B" has 2 favorite recipes with the ID's "4" and "5".
We need to make sure that if user A sends a DELETE command to /Recipes/4 that he will get a Forbidden (403) response.
What I would normally do...
What I would normally do is make them first call an authentication method, and send them some sort of auth-token that is valid for 30 minutes or so. Typically this token would be passed via a cookie.
What is the pure solution?
Is the pure REST solution to have them pass it as a variable in the query string? Are cookies the devil? Should the token be used as a segment of the URL (as opposed to a query string parameter)? Is there something else that answers this question clearly?
Pass the token in the authorization header. That's what it is designed for. See http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p7-auth-12.html
Treat the auth token as a resource.
You authenticate by GETting an auth token with parameters being credentials (basic auth over https for example).
Logout by DELETE'ing the auth token resource you got when logging in.
A simple stateless and cookie free solution would be giving each of your users an identical token.
There are ways to generate those tokens so that they are sparse enough for security concerns.
e.g. https://www.grc.com/passwords.htm
Suppose you have user A and user B. You generate a token X for user A and a token Y for user B.
So the user A will use something like /X/Recipes/1
and user B will use something like /Y/Recipes/4
It's safe because user A is the only one knows his token and as I mentioned before, the way you generate tokens can make sure it's "impossible" for others to guess that token.
So if someone else, like user B uses some other token in the url, say /Z/Recipes/1, you should be able to recognize and return a corresponding error message.
You can let user deliver the token in url, like I showed above, or embed it in HTTP request as Autherticantion message.