Is using sessions in a RESTful API really violating RESTfulness? I have seen many opinions going either direction, but I'm not convinced that sessions are RESTless. From my point of view:
authentication is not prohibited for RESTfulness (otherwise there'd be little use in RESTful services)
authentication is done by sending an authentication token in the request, usually the header
this authentication token needs to be obtained somehow and may be revoked, in which case it needs to be renewed
the authentication token needs to be validated by the server (otherwise it wouldn't be authentication)
So how do sessions violate this?
client-side, sessions are realized using cookies
cookies are simply an extra HTTP header
a session cookie can be obtained and revoked at any time
session cookies can have an infinite life time if need be
the session id (authentication token) is validated server-side
As such, to the client, a session cookie is exactly the same as any other HTTP header based authentication mechanism, except that it uses the Cookie header instead of the Authorization or some other proprietary header. If there was no session attached to the cookie value server-side, why would that make a difference? The server side implementation does not need to concern the client as long as the server behaves RESTful. As such, cookies by themselves should not make an API RESTless, and sessions are simply cookies to the client.
Are my assumptions wrong? What makes session cookies RESTless?
First of all, REST is not a religion and should not be approached as such. While there are advantages to RESTful services, you should only follow the tenets of REST as far as they make sense for your application.
That said, authentication and client side state do not violate REST principles. While REST requires that state transitions be stateless, this is referring to the server itself. At the heart, all of REST is about documents. The idea behind statelessness is that the SERVER is stateless, not the clients. Any client issuing an identical request (same headers, cookies, URI, etc) should be taken to the same place in the application. If the website stored the current location of the user and managed navigation by updating this server side navigation variable, then REST would be violated. Another client with identical request information would be taken to a different location depending on the server-side state.
Google's web services are a fantastic example of a RESTful system. They require an authentication header with the user's authentication key to be passed upon every request. This does violate REST principles slightly, because the server is tracking the state of the authentication key. The state of this key must be maintained and it has some sort of expiration date/time after which it no longer grants access. However, as I mentioned at the top of my post, sacrifices must be made to allow an application to actually work. That said, authentication tokens must be stored in a way that allows all possible clients to continue granting access during their valid times. If one server is managing the state of the authentication key to the point that another load balanced server cannot take over fulfilling requests based on that key, you have started to really violate the principles of REST. Google's services ensure that, at any time, you can take an authentication token you were using on your phone against load balance server A and hit load balance server B from your desktop and still have access to the system and be directed to the same resources if the requests were identical.
What it all boils down to is that you need to make sure your authentication tokens are validated against a backing store of some sort (database, cache, whatever) to ensure that you preserve as many of the REST properties as possible.
I hope all of that made sense. You should also check out the Constraints section of the wikipedia article on Representational State Transfer if you haven't already. It is particularly enlightening with regard to what the tenets of REST are actually arguing for and why.
First, let's define some terms:
RESTful:
One can characterise applications conforming to the REST constraints
described in this section as "RESTful".[15] If a service violates any
of the required constraints, it cannot be considered RESTful.
according to wikipedia.
stateless constraint:
We next add a constraint to the client-server interaction:
communication must be stateless in nature, as in the
client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3),
such that each request from client to server must contain all of the
information necessary to understand the request, and cannot take
advantage of any stored context on the server. Session state is
therefore kept entirely on the client.
according to the Fielding dissertation.
So server side sessions violate the stateless constraint of REST, and so RESTfulness either.
As such, to the client, a session cookie is exactly the same as any
other HTTP header based authentication mechanism, except that it uses
the Cookie header instead of the Authorization or some other
proprietary header.
By session cookies you store the client state on the server and so your request has a context. Let's try to add a load balancer and another service instance to your system. In this case you have to share the sessions between the service instances. It is hard to maintain and extend such a system, so it scales badly...
In my opinion there is nothing wrong with cookies. The cookie technology is a client side storing mechanism in where the stored data is attached automatically to cookie headers by every request. I don't know of a REST constraint which has problem with that kind of technology. So there is no problem with the technology itself, the problem is with its usage. Fielding wrote a sub-section about why he thinks HTTP cookies are bad.
From my point of view:
authentication is not prohibited for RESTfulness (otherwise there'd be little use in RESTful services)
authentication is done by sending an authentication token in the request, usually the header
this authentication token needs to be obtained somehow and may be revoked, in which case it needs to be renewed
the authentication token needs to be validated by the server (otherwise it wouldn't be authentication)
Your point of view was pretty solid. The only problem was with the concept of creating authentication token on the server. You don't need that part. What you need is storing username and password on the client and send it with every request. You don't need more to do this than HTTP basic auth and an encrypted connection:
Figure 1. - Stateless authentication by trusted clients
You probably need an in-memory auth cache on server side to make things faster, since you have to authenticate every request.
Now this works pretty well by trusted clients written by you, but what about 3rd party clients? They cannot have the username and password and all the permissions of the users. So you have to store separately what permissions a 3rd party client can have by a specific user. So the client developers can register they 3rd party clients, and get an unique API key and the users can allow 3rd party clients to access some part of their permissions. Like reading the name and email address, or listing their friends, etc... After allowing a 3rd party client the server will generate an access token. These access token can be used by the 3rd party client to access the permissions granted by the user, like so:
Figure 2. - Stateless authentication by 3rd party clients
So the 3rd party client can get the access token from a trusted client (or directly from the user). After that it can send a valid request with the API key and access token. This is the most basic 3rd party auth mechanism. You can read more about the implementation details in the documentation of every 3rd party auth system, e.g. OAuth. Of course this can be more complex and more secure, for example you can sign the details of every single request on server side and send the signature along with the request, and so on... The actual solution depends on your application's need.
Cookies are not for authentication. Why reinvent a wheel? HTTP has well-designed authentication mechanisms. If we use cookies, we fall into using HTTP as a transport protocol only, thus we need to create our own signaling system, for example, to tell users that they supplied wrong authentication (using HTTP 401 would be incorrect as we probably wouldn't supply Www-Authenticate to a client, as HTTP specs require :) ). It should also be noted that Set-Cookie is only a recommendation for client. Its contents may be or may not be saved (for example, if cookies are disabled), while Authorization header is sent automatically on every request.
Another point is that, to obtain an authorization cookie, you'll probably want to supply your credentials somewhere first? If so, then wouldn't it be RESTless? Simple example:
You try GET /a without cookie
You get an authorization request somehow
You go and authorize somehow like POST /auth
You get Set-Cookie
You try GET /a with cookie. But does GET /a behave idempotently in this case?
To sum this up, I believe that if we access some resource and we need to authenticate, then we must authenticate on that same resource, not anywhere else.
Actually, RESTfulness only applies to RESOURCES, as indicated by a Universal Resource Identifier. So to even talk about things like headers, cookies, etc. in regards to REST is not really appropriate. REST can work over any protocol, even though it happens to be routinely done over HTTP.
The main determiner is this: if you send a REST call, which is a URI, then once the call makes it successfully to the server, does that URI return the same content, assuming no transitions have been performed (PUT, POST, DELETE)? This test would exclude errors or authentication requests being returned, because in that case, the request has not yet made it to the server, meaning the servlet or application that will return the document corresponding to the given URI.
Likewise, in the case of a POST or PUT, can you send a given URI/payload, and regardless of how many times you send the message, it will always update the same data, so that subsequent GETs will return a consistent result?
REST is about the application data, not about the low-level information required to get that data transferred about.
In the following blog post, Roy Fielding gave a nice summary of the whole REST idea:
http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/5841
"A RESTful system progresses from one steady-state to the
next, and each such steady-state is both a potential start-state
and a potential end-state. I.e., a RESTful system is an unknown
number of components obeying a simple set of rules such that they
are always either at REST or transitioning from one RESTful
state to another RESTful state. Each state can be completely
understood by the representation(s) it contains and the set of
transitions that it provides, with the transitions limited to a
uniform set of actions to be understandable. The system may be
a complex state diagram, but each user agent is only able to see
one state at a time (the current steady-state) and thus each
state is simple and can be analyzed independently. A user, OTOH,
is able to create their own transitions at any time (e.g., enter
a URL, select a bookmark, open an editor, etc.)."
Going to the issue of authentication, whether it is accomplished through cookies or headers, as long as the information isn't part of the URI and POST payload, it really has nothing to do with REST at all. So, in regards to being stateless, we are talking about the application data only.
For example, as the user enters data into a GUI screen, the client is keeping track of what fields have been entered, which have not, any required fields that are missing etc. This is all CLIENT CONTEXT, and should not be sent or tracked by the server. What does get sent to the server is the complete set of fields that need to be modified in the IDENTIFIED resource (by the URI), such that a transition occurs in that resource from one RESTful state to another.
So, the client keeps track of what the user is doing, and only sends logically complete state transitions to the server.
As I understand, there are two types of state when we are talking about sessions
Client and Server Interaction State
Resource State
Stateless constraint here refers to the second type in Rest. Using cookies (or local storage) does not violate Rest since it is related to the first.
Fielding says: 'Each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client.'
The thing here is that every request to be fulfilled on the server needs the all necessary data from the client. Then this is considered as stateless. And again, we're not talking about cookies here, we're talking about resources.
HTTP transaction, basic access authentication, is not suitable for RBAC, because basic access authentication uses the encrypted username:password every time to identify, while what is needed in RBAC is the Role the user wants to use for a specific call.
RBAC does not validate permissions on username, but on roles.
You could tric around to concatenate like this: usernameRole:password, but this is bad practice, and it is also inefficient because when a user has more roles, the authentication engine would need to test all roles in concatenation, and that every call again. This would destroy one of the biggest technical advantages of RBAC, namely a very quick authorization-test.
So that problem cannot be solved using basic access authentication.
To solve this problem, session-maintaining is necessary, and that seems, according to some answers, in contradiction with REST.
That is what I like about the answer that REST should not be treated as a religion. In complex business cases, in healthcare, for example, RBAC is absolutely common and necessary. And it would be a pity if they would not be allowed to use REST because all REST-tools designers would treat REST as a religion.
For me there are not many ways to maintain a session over HTTP. One can use cookies, with a sessionId, or a header with a sessionId.
If someone has another idea I will be glad to hear it.
i think token must include all the needed information encoded inside it, which makes authentication by validating the token and decoding the info
https://www.oauth.com/oauth2-servers/access-tokens/self-encoded-access-tokens/
No, using sessions does not necessarily violate RESTfulness. If you adhere to the REST precepts and constraints, then using sessions - to maintain state - will simply be superfluous. After all, RESTfulness requires that the server not maintain state.
Sessions are not RESTless
Do you mean that REST service for http-use only or I got smth wrong? Cookie-based session must be used only for own(!) http-based services! (It could be a problem to work with cookie, e.g. from Mobile/Console/Desktop/etc.)
if you provide RESTful service for 3d party developers, never use cookie-based session, use tokens instead to avoid the problems with security.
Related
I am building an app to better understand Restful back-ends with clients that makes calls to it. I am using slim to handle routing and service calls. I am stuck on two things though.
Part 1 - If restful APIs should not use sessions how do I keep information like authenticated and user_id available? It was my understanding storing that information in a cookie was a bad practice. Once a user authenticated normally I would use $_SESSION['uid'].
Part 2 - This part is more confusing to me. I am using Twig for front-end (not a cool js guy). Doing so all on the same server I use slim-view to render twig. But that means my back-end is not sending JSON it is doing everything. How is something like this separated? Is it worth while?
Part one
One method is create a dynamic API key that is temporary, with this temp key you can then authenticate and authorize any request coming from the client.
On the server side you can store this temp API key inside a table with some fields to keep track when the key was last used and how long the key is valid. By doing this you can invalidate API keys at the server side
The client can store the key wherever but if you are going to use PHP then I suggest storing it in the session
sidenote: This answer is based on an API I worked on. The field static in the table api_key is used for keys that only can be used to login an user and obtain a dynamic key that then was used for authentication and authorization.
This was due to the fact that our client was written in JS and the static API key was plain visible in the source code.
So the client first had to issue a login request before obtaining a "legit" api key
part 2
You need to decouple your client project from you server project. Your client should only ever receive data (e.g. JSON) from the server, your server should never worry about how to present the data only about sending it the client.
The client can be written in any language and can even be hosted somewhere else. The only thing a client can't do is contact the database directly. It has to request every piece of information straight from the server
There is any way to check the login status through different programming language?
Right now I'm using three session (same name) that starts at the same time after the login process, using ajax.
Right now, the login.html form is processed on three files: login.aspx, login.asp and login.php but it's seems too slow and weird. I'm combining three different services from the same company into one, after re-building the users and others common tables in mysql, everything seems to work fine, but I'm really scared about security bugs.
Just to let you you know, I have to check the login session status before any ajax callback, so if the user is working on an ASP page calling PHP through Ajax, may be that the session is still active on the ASP, but expired on the php file.
Any valid method to check all in one time? I can also accept a cookie solution but how to make it readable between php, asp and .net?
This sounds like single sign-on to me. Let's try to split the problem.
There is any way to check the login status through different programming language?
You're not really interested in the language used. Any language, given the same info and algorithm, would decode with success the same encrypted data. I guess you're instead having problems because PHP's application logic regarding this point is different from the ASP's one.
So for the first point, you can
Implement / normalize the same session checking logic among all of your apps. This is probably unfeasible, because you might be using Laravel here, and ASP.Net on the other, and the two are probably slightly different in this regard. If you can, do this, or...
Look into JSON Web Tokens. I won't go into detail, but these were more or less designed to solve this class of problems. They are also easy to handle, but be aware, there are aspects you have to take care of when using them for user authentication.
[...] Just to let you you know, I have to check the login session status before any ajax callback, so if the user is working on an ASP page calling PHP through Ajax, may be that the session is still active on the ASP, but expired on the php file.
Not to be that guy, but some concepts are somewhat deformed here. Sessions don't expire on files; they normally are setup with a given expiration time and a given domain. So generally speaking, a session opened from a PHP app, and stored on a cookie, then read from an ASP one shouldn't change, given that no difference exists between the two app's session handling logic.
Any valid method to check all in one time? I can also accept a cookie solution but how to make it readable between php, asp and .net?
For both of the solutions i suggested above is, especially for the cookie one, it's important you make the apps absolutely identical in respect to session handling. While this is trivial with JWT (as there's barely any logic on the app's side), this may prove to be harder with cookies if the authentication logic comes from some one else's code (as in a framework).
I haven't asked about single sign-out, and at this point i'm afraid to ask :). But these are some guidelines:
If going the cookie route, be aware of cookie's domain. A cookie is normally valid for every request coming from the website domain (name.com), but you may have some of your apps under a subdomain (like, phpapp.name.com). In this case, be sure the cookie created from the given app is valid for the whole domain, and not just the subdomain. And make the apps available at subdomains / pages under the same domain. Cookies don't work cross-domain, and you have to deal with that, since cookie domain policy is enforced at browser level.
Launching three AJAX calls means triggering three login procedures. I suppose all of these would terminate, at some point in the future, and all of those would be storing / rewriting the cookie. If the apps understand the same cookie, it's mandatory you open the login process on just one of them. This would store the cookie, which would then be automatically picked app from, say, a page in the second app, giving you a seamless transition into a logged-state in the second app.
JWT would normally require some JS work, which you may like since the same script can easily be loaded in all of your apps. On the other side, you can be sure that different server libraries handling JWT would all work the same for you, thus ensuring compatibility.
Personally, i would look into JSON Web Tokens.
You can develop your own session provider which stores data in a separate place (for ex. in database or files). Then everything you need to do is write some code in every environment to handle your session information from that provider. Because you use only one source to store session information there will be no problem with synchronization between any of yours environment.
If you need then you can use a webservice for exchange session information between every environment and session provider. Every application can use security connection to get and set information about session from that session webservice.
I think you can do this!You can create provider which stores data into database. Then Write some cool code to manage your provider.You can also use webapp or sevice.Every service use security to get and put information.
I've been on stack overflow for the last hour researching this topic so I thought I'd just ask all my specific questions. I'm building a web app currently using Laravel (PHP) for the API and Angular for the front. I've looked at oAuth but it's a little daunting atm so I was hoping to implement a simpler solution and then rebuild it in when necessary.
The flow I'm currently implements goes as follows. Angular posts the user credentials (over https) to my rest backend and this simply returns a generated string (this will probably be random or crytographicaly generated). This string is then stored as a cookie or whatever browser state I find suitable and then attached to every API request along with a user id that angular makes as an extra parameter or request header or something. The API uses this to check if the user has access to the requested resource and responds accordingly. I'd probably also add a expiry time on the string which would be reset after every request.
My question is really if this is an acceptable flow? In terms of security what issues am I most likely to face with this? CSRF? Session fixation?
I know this is a question that's been asked a couple times before but I was just hoping for a fresh discussion and be pointed towards relevant information.
If I'm understanding you correctly, this is a model I've seen in plenty of APIs, especially in the stateless SOA world. The "string" you're talking about is most commonly referred to as an "auth token." And all non-public API methods require the token (and for it to be valid -- expiration is essential, else someone could grab an old token) to be included with every request (with or without username -- the token should be uniquely identifiable so as to make that unnecessary, but it doesn't hurt), which means before you do anything you have to call the Login API (which does not require a token, natch) to get one before you do anything.
You may want to have your token's expiration refresh on every use (idle timeout), or else you will need to have your clients know they may need to refresh the token (i.e get a new one) every once in a while (which is somewhat more secure than an idle timeout one).
What you describe is some kind of basic session implementation. Since REST have a stateless constraints which denies such things, I don't think that this is an acceptable solution. Afaik you have to send the username and password with every request from the trustable clients. If you have 3rd party clients, then you have to generate api keys and access tokens for them (OAuth can solve that part). If you want to know more about REST constraints, then read the Fielding dissertation.
Thanks for you input everyone. Ultimately I decided to have a look into OAuth 2 again as suggested. What I was trying to create was pretty much an OAuth flow anyway... Instead of trying to recreate the wheel I looked at other people's implementations of OAuth in PHP (and Laravel) and this practical implementation really helped me get the idea.
I used this package in the end
https://github.com/thephpleague/oauth2-server
Wrapped for laravel
https://github.com/lucadegasperi/oauth2-server-laravel
I was a bit unsure about how OAuth would be implemented for my use case as it was just for internal usage. I discovered that because I had a high trust of the client a great flow to use would be the Resource owner credentials grant.
The only real issue I face now is securing the client id and client secret. It being stored on client side is definitely an issue but form my understanding that's just one of the issues of OAuth. Fortunately if it's ever compromised I can revoke and reissue.
Anyone else that comes across this with a similar question should have a look at the following links:
http://alexbilbie.com/2013/02/a-guide-to-oauth-2-grants/
https://www.rfc-editor.org/rfc/rfc6749
They really helped me understand OAuth 2.
I have a script that uses JSONP to make cross domain ajax calls. This works great but my question is, is there a way to prevent other sites from accessing and getting data from these URL's? I basically would like to make a list of sites that are allowed and only return data if they are in the list. I am using PHP and figure I might be able to use "HTTP_REFERER" but have read that some browsers will not send this info.... ??? Any ideas?
Thanks!
There really is no effective solution. If your JSON is accessible through the browser, then it is equally accessible to other sites. To the web server a request originating from a browser or another server are virtually indistinguishable aside from the headers. Like ILMV commented, referrers (and other headers) can be falsified. They are after all, self-reported.
Security is never perfect. A sufficiently determined person can overcome any security measures in place, but the goal of security is to create a high enough deterrent that laypeople and or most people would be dissuaded from putting the time and resources necessary to compromise the security.
With that thought in mind, you can create a barrier of entry high enough that other sites would probably not bother making requests with the barriers of entry put into place. You can generate single use tokens that are required to grab the json data. Once a token is used to grab the json data, the token is then subsequently invalidated. In order to retrieve a token, the web page must be requested with a token embedded within the page in javascript that is then put into the ajax call for the json data. Combine this with time-expiring tokens, and sufficient obfuscation in the javascript and you've created a high enough barrier.
Just remember, this isn't impossible to circumvent. Another website could extract the token out of the javascript, and or intercept the ajax call and hijack the data at multiple points.
Do you have access to the servers/sites that you would like to give access to the JSONP?
What you could do, although not ideal is to add a record to a db of the IP on the page load that is allowed to view the JSONP, then on the jsonp load, check if that record exists. Perhaps have an expiry on the record if appropriate.
e.g.
http://mysite.com/some_page/ - user loads page, add their IP to the database of allowed users
http://anothersite.com/anotherpage - as above, add to database
load JSONP, check the IP exists in the database.
After one hour delete the record from the db, so another page load would be required for example
Although this could quite easily be worked around if the scraper (or other sites) managed to work out what method you are using to allow users to view the JSONP, they'd only have to hit the page first.
How about using a cookie that holds a token used with every jsonp request?
Depending on the setup you can also use a variable if you don't want to use cookies.
Working with importScript form the Web Worker is quite the same as jsonp.
Make a double check like theAlexPoon said. Main-script to web worker, web worker to sever and back with security query. If the web worker answer to the main script without to be asked or with the wrong token, its better to forward your website to the nirvana. If the server is asked with the wrong token don't answer. Cookies will not be send with an importScript request, because document is not available at web worker level. Always send security relevant cookies with a post request.
But there are still a lot of risks. The man in the middle knows how.
I'm certain you can do this with htaccess -
Ensure your headers are sending "HTTP_REFERER" - I don't know any browser that wont send it if you tell it to. (if you're still worried, fall back gracefully)
Then use htaccess to allow/deny access from the right referer.
# deny all except those indicated here
order deny,allow
deny from all
allow from .*domain\.com.*
I have a web application that pulls data from my newly created JSON API.
My static HTML pages dynamically calls the JSON API via JavaScript from the static HTML page.
How do I restrict access to my JSON API so that only I (my website) can call from it?
In case it helps, my API is something like: http://example.com/json/?var1=x&var2=y&var3=z... which generates the appropriate JSON based on the query.
I'm using PHP to generate my JSON results ... can restricting access to the JSON API be as simple as checking the $_SERVER['HTTP_REFERER'] to ensure that the API is only being called from my domain and not a remote user?
I think you might be misunderstanding the part where the JSON request is initiated from the user's browser rather than from your own server. The static HTML page is delivered to the user's browser, then it turns around and executes the Javascript code on the page. This code opens a new connection back to your server to obtain the JSON data. From your PHP script's point of view, the JSON request comes from somewhere in the outside world.
Given the above mechanism, there isn't much you can do to prevent anybody from calling the JSON API outside the context of your HTML page.
The usual method for restricting access to your domain is prepend the content with something that runs infinitely.
For example:
while(1);{"json": "here"} // google uses this method
for (;;);{"json": "here"} // facebook uses this method
So when you fetch this via XMLHttpRequest or any other method that is restricted solely to your domain, you know that you need to parse out the infinite loop. But if it is fetched via script node:
<script src="http://some.server/secret_api?..."></script>
It will fail because the script will never get beyond the first statement.
In my opinion, you can't restrict the access, only make it harder. It's a bit like access-restriction by obscurity. Referrers can be easily forged, and even with the short-lived key a script can get the responses by constantly refreshing the key.
So, what can we do?
Identify the weakness here:
http://www.example.com/json/getUserInfo.php?id=443
The attacker now can easily request all user info from 1 to 1.000.000 in a loop. The weak point of auto_increment IDs is their linearity and that they're easy to guess.
Solution: use non-numeric unique identifiers for your data.
http://www.example.com/json/getUserInfo.php?userid=XijjP4ow
You can't loop over those. True, you can still parse the HTML pages for keys for all kinds of keys, but this type of attack is different (and more easily avoidable) problem.
Downside: of course you can't use this method to restrict queries that aren't key-dependent, e.g. search.
Any solution here is going to be imperfect if your static pages that use the API need to be on the public Internet. Since you need to be able to have the client's browser send the request and have it be honored, it's possibly for just about anyone to see exactly how you are forming that URL.
You can have the app behind your API check the http referrer, but that is easy to fake if somebody wants to.
If it's not a requirement for the pages to be static, you could try something where you have a short-lived "key" generated by the API and included in the HTML response of the first page which gets passed along as a parameter back to the API. This would add overhead to your API though as you would have to have the server on that end maintain a list of "keys" that are valid, how long they are valid for, etc.
So, you can take some steps which won't cost a lot but aren't hard to get around if someone really wants to, or you can spend more time to make it a tiny bit harder, but there is no perfect way to do this if your API has to be publically-accessible.
The short answer is: anyone who can access the pages of your website will also be able to access your API.
You can attempt to make using your API more difficult by encrypting it in various ways, but since you'll have to include JavaScript code for decrypting the output of your API, you're just going to be setting yourself up for an arms race with anyone who decides they want to use your API through other means. Even if you use short-lived keys, a determined "attacker" could always just scrape your HTML (along with the current key) just before using the API.
If all you want to do is prevent other websites from using your API on their web pages then you could use Referrer headers but keep in mind that not all browsers send Referrers (and some proxies strip them too!). This means you'd want to allow all requests missing a referrer, and this would only give you partial protection. Also, Referrers can be easily forged, so if some other website really wants to use your API they can always just spoof a browser and access your API from their servers.
Are you, or can you use a cookie based authentication? My experience is based on ASP.NET forms authentication, but the same approach should be viable with PHP with a little code.
The basic idea is, when the user authenticates through the web app, a cookie that has an encrypted value is returned to the client browser. The json api would then use that cookie to validate the identity of the caller.
This approach obviously requires the use of cookies, so that may or may not be a problem for you.
Sorry, maybe I'm wrong but... can it be made using HTTPS?
You can (?) have your API accessible via https://example.com/json/?var1=x&var2=y, thus only authenticated consumer can get your data...
Sorry, there's no DRM on the web :-)
You can not treat HTML as a trusted client. It's a plain text script interpreted on other people's computers as they see fit. Whatever you allow your "own" JavaScript code do you allow anyone. You can't even define how long it's "yours" with Greasemonkey and Firebug in the wild.
You must duplicate all access control and business logic restrictions in the server as if none of it were present in your JavaScript client.
Include the service in your SSO, restrict the URLs each user has access to, design the service keeping wget as the client in mind, not your well behaved JavaScript code.