Is it possible to access Provisioning API with service account? - oauth-2.0

My service account scopes are : https://apps-apis.google.com/a/feeds/user/ and DriveScope.DRIVE
I authorized this same scope in "Manage third party OAuth Client access" in domain settings for my service account Id.
I use the java client of the provisioning api.
I build my credentials with the google oauth client with a GoogleCredential.Builder :
credBuilder.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(config.serviceAccountId)
.setServiceAccountPrivateKeyFromP12File(new File(config.keyFilePath))
.setServiceAccountScopes(SCOPES);
.setServiceAccountUser("admin.of.my#domain.com")
I try to authorize my request to the provisioning api with
userService = new UserService(config.repositoryId);
userService.setOAuth2Credentials(oAuthCredentials);
where oAuthCredentials are my previously built Service credentials.
With that configuration i can access files and collections from the Google Drive of any user of my domain. But i can't acces the list of users of my domain with those credentials.
If i dont specify the service account user, it doesn't work either
Here is the stack trace i get :
com.google.gdata.util.ServiceForbiddenException: You are not authorized to access this API.
<HTML>
<HEAD>
<TITLE>You are not authorized to access this API.</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>You are not authorized to access this API.</H1>
<H2>Error 403</H2>
</BODY>
</HTML>
at com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:605)
at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:564)
at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:560)
at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:538)
at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:536)
at com.google.gdata.client.Service.getFeed(Service.java:1135)
at com.google.gdata.client.Service.getFeed(Service.java:998)
at com.google.gdata.client.GoogleService.getFeed(GoogleService.java:645)
at com.google.gdata.client.Service.getFeed(Service.java:1017)
at com.google.gdata.client.appsforyourdomain.AppsForYourDomainService.getFeed(AppsForYourDomainService.java:137)
at foo.bar.baz.eci.gdrive.service.BaseService$1.doTry(BaseService.java:125)
at foo.bar.baz.eci.gdrive.service.BaseService$1.doTry(BaseService.java:1)
at foo.bar.baz.eci.gdrive.service.backoff.BackoffRequest.execute(BackoffRequest.java:50)
at foo.bar.baz.eci.gdrive.service.BaseService.getFeedWithBackoff(BaseService.java:129)
at foo.bar.baz.eci.gdrive.service.BaseService.retrieveAllEntries(BaseService.java:90)
at foo.bar.baz.eci.gdrive.service.GappsUserService.getAllUserFeed(GappsUserService.java:57)
at foo.bar.baz.eci.gdrive.GdriveContentProviderFactory.doDiscover(GdriveContentProviderFactory.java:67)
... 19 more
And the logging from the client lib :
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setPrivateHeader
PLUS FIN: Authorization: <Not Logged>
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setPrivateHeader
PLUS FIN: Authorization: <Not Logged>
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setPrivateHeader
PLUS FIN: Authorization: <Not Logged>
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setHeader
PLUS FIN: User-Agent: gdocsRepo GData-Java/1.47.1(gzip)
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setHeader
PLUS FIN: User-Agent: gdocsRepo GData-Java/1.47.1(gzip)
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setHeader
PLUS FIN: User-Agent: gdocsRepo GData-Java/1.47.1(gzip)
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setHeader
PLUS FIN: Accept-Encoding: gzip
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setHeader
PLUS FIN: Accept-Encoding: gzip
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setHeader
PLUS FIN: Accept-Encoding: gzip
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setHeader
PLUS FIN: GData-Version: 1.0
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setHeader
PLUS FIN: GData-Version: 1.0
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest setHeader
PLUS FIN: GData-Version: 1.0
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
FIN: 403 You are not authorized to access this API.
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
FIN: 403 You are not authorized to access this API.
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
FIN: 403 You are not authorized to access this API.
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Content-Encoding: gzip
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Content-Encoding: gzip
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Content-Encoding: gzip
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Content-Length: 151
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Content-Length: 151
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Content-Length: 151
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: null: HTTP/1.1 403 You are not authorized to access this API.
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: null: HTTP/1.1 403 You are not authorized to access this API.
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: null: HTTP/1.1 403 You are not authorized to access this API.
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Expires: Wed, 21 Nov 2012 14:17:37 GMT
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Expires: Wed, 21 Nov 2012 14:17:37 GMT
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Expires: Wed, 21 Nov 2012 14:17:37 GMT
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: X-XSS-Protection: 1; mode=block
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: X-XSS-Protection: 1; mode=block
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: X-XSS-Protection: 1; mode=block
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: X-Frame-Options: SAMEORIGIN
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: X-Frame-Options: SAMEORIGIN
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: X-Frame-Options: SAMEORIGIN
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Date: Wed, 21 Nov 2012 14:17:37 GMT
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Date: Wed, 21 Nov 2012 14:17:37 GMT
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Date: Wed, 21 Nov 2012 14:17:37 GMT
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Content-Type: text/html; charset=UTF-8
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Content-Type: text/html; charset=UTF-8
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Content-Type: text/html; charset=UTF-8
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Server: GSE
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Server: GSE
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Server: GSE
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: X-Content-Type-Options: nosniff
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: X-Content-Type-Options: nosniff
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: X-Content-Type-Options: nosniff
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Cache-Control: private, max-age=0
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Cache-Control: private, max-age=0
21 nov. 2012 15:17:37 com.google.gdata.client.http.HttpGDataRequest execute
PLUS FIN: Cache-Control: private, max-age=0

After investigation it seems that getting a 403 error happens if the account that is set in .setServiceAccountUser("admin.of.my#domain.com") is not a "Super Admin" of the domain.
However in the case above "admin.of.my#domain.com" is indeed a Super Admin of the domain. Also the code works well with any other Super Admin of the domain which leads to believe that there is something wrong with the account "admin.of.my#domain.com" in particular.
If this happens to anyone else - a.k.a. an account set as "Super Admin" which does not work to access Admins-only APIs through Service Accounts - make sure you let us know in the comments below and we'll investigate further if this impacts lots of people.

Now provisioning APIs have been deprecated as of 15th of May 2013. They have introduced new set of APIs called Directory APIs which solves your problem.

Related

Twitter oauth/request_token API using Fiddler results in 401 error

I am trying to use fiddler to test the oauth/request_token api but am getting a 'Failed to validate oauth signature and token' 401 error. I copied the authorization header values directly from my application and added an oauth_callback header. I am trying to follow the example in the following documentation:
https://dev.twitter.com/docs/api/1/post/oauth/request_token.
Any help would be greatly appreciated.
REQUEST:
POST https://api.twitter.com/oauth/request_token HTTP/1.1
Authorization: OAuth oauth_callback="http%3A%2F%2Flocalhost%3A61921%2Ftwitter%2Fprocesscallback", oauth_consumer_key="XXXXXXXXXXXXXXXXXXXXX", oauth_nonce="53891723ad7b32501c669d97f56c6d47", oauth_signature="qzN516EVspIA0NWBbpND83YcTr4%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1402955245",
oauth_token="2514015781-KqTbOPPag7p0CYQ6xByIibV3WEk8xLsWrhb9U4M",
oauth_version="1.0"
Host: api.twitter.com
Content-Length: 0
RESPONSE:
HTTP/1.1 401 Unauthorized
cache-control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0
content-length: 44
content-type: text/html; charset=utf-8
date: Mon, 16 Jun 2014 21:54:56 GMT
expires: Tue, 31 Mar 1981 05:00:00 GMT
last-modified: Mon, 16 Jun 2014 21:54:56 GMT
pragma: no-cache
server: tfe
set-cookie: _twitter_sess=BAh7CDoPY3JlYXRlZF9hdGwrCEIJraZGAToHaWQiJTlmOTQ3Y2MyYWNlMTkx%250AYTMyYzVlZmYyMTA4ZjU4ZTdkIgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVy%250AOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--3afebfe1105e8a7315baba72651e76a24f53e6d2; domain=.twitter.com; path=/; secure; HttpOnly
set-cookie: guest_id=v1%3A140295569643962216; Domain=.twitter.com; Path=/; Expires=Wed, 15-Jun-2016 21:54:56 UTC
status: 401 Unauthorized
strict-transport-security: max-age=631138519
vary: Accept-Encoding
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-mid: d31abfd0b6cbb0aa6434a6ffc6efdfac089ab0a5
x-runtime: 0.01273
x-transaction: 2dd94ca53f553801
x-ua-compatible: IE=edge,chrome=1
x-xss-protection: 1; mode=block
Failed to validate oauth signature and token

Change of behavior: GetUser now returns real user if alias address specified

It looks like something has recently changes with the Provisioning API when getting a user account:
https://developers.google.com/google-apps/provisioning/#retrieving_users_experimental
previously, if you specified an address that was an Alias/Nickname, not a user, you got a 1301 error. Now it returns results for the primary user. Here's what GAM shows:
Verify that admin2# is an alias of admin:
C:\gam>gam info alias admin2
send: 'GET https://apps-apis.google.com/a/feeds/alias/2.0/jay.powerposters.org/a
dmin2#jay.powerposters.org HTTP/1.1\r\nAccept-Encoding: identity\r\nHost: apps-a
pis.google.com\r\nContent-Type: application/atom+xml\r\nAuthorization: OAuth rea
lm="", oauth_nonce="xxx", oauth_timestamp="xxx", oauth_consumer_key=
"xxxx", oauth_signature_method="HMAC-SHA1", oa
uth_version="1.0", oauth_token="xxx"
, oauth_signature="xxx"\r\nUser-Agent: Google App
s Manager 2.54 / jay#ditoweb.com (Jay Lee) / Python 2.7.3 final / Windows-7-6.1.
7601-SP1 AMD64 / GData-Python 2.0.14+20110902+custom_mods\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/atom+xml; charset=UTF-8
header: Expires: Thu, 15 Nov 2012 21:57:50 GMT
header: Date: Thu, 15 Nov 2012 21:57:50 GMT
header: Cache-Control: private, max-age=0, must-revalidate, no-transform
header: Vary: Accept, X-GData-Authorization, GData-Version
header: GData-Version: 1.0
header: Last-Modified: Thu, 15 Nov 2012 21:57:50 GMT
header: X-Content-Type-Options: nosniff
header: X-Frame-Options: SAMEORIGIN
header: X-XSS-Protection: 1; mode=block
header: Server: GSE
header: Transfer-Encoding: chunked
Alias Email: admin2#jay.powerposters.org
User Email: admin#jay.powerposters.org
Get "user" alias2:
C:\gam>gam info user admin2
send: 'GET https://apps-apis.google.com/a/feeds/user/2.0/jay.powerposters.org/ad
min2#jay.powerposters.org HTTP/1.1\r\nAccept-Encoding: identity\r\nHost: apps-ap
is.google.com\r\nContent-Type: application/atom+xml\r\nAuthorization: OAuth real
m="", oauth_nonce="xxx", oauth_timestamp="xxx", oauth_consumer_key="
xxx", oauth_signature_method="HMAC-SHA1", oau
th_version="1.0", oauth_token="xxx",
oauth_signature="xxx"\r\nUser-Agent: Google Apps Man
ager 2.54 / jay#ditoweb.com (Jay Lee) / Python 2.7.3 final / Windows-7-6.1.7601-
SP1 AMD64 / GData-Python 2.0.14+20110902+custom_mods\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/atom+xml; charset=UTF-8
header: Expires: Thu, 15 Nov 2012 21:59:32 GMT
header: Date: Thu, 15 Nov 2012 21:59:32 GMT
header: Cache-Control: private, max-age=0, must-revalidate, no-transform
header: Vary: Accept, X-GData-Authorization, GData-Version
header: GData-Version: 1.0
header: Last-Modified: Thu, 15 Nov 2012 21:59:32 GMT
header: X-Content-Type-Options: nosniff
header: X-Frame-Options: SAMEORIGIN
header: X-XSS-Protection: 1; mode=block
header: Server: GSE
header: Transfer-Encoding: chunked
User: admin2#jay.powerposters.org
First Name: Admin+
Last Name: USER
Is an admin: true
Has agreed to terms: true
IP Whitelisted: false
Account Suspended: false
Must Change Password: false
This new behavior breaks GAM commands like "gam whatis " since that command relied on getting the 1301 when trying to access the address as a user. I can imagine other apps that functioned similarly also broke.
Jay

document list api create failed

The request below fails and I am not able to figure out why, any insights?
var atom = ["<?xml version='1.0' encoding='UTF-8'?>",
'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">',
'<category scheme="http://schemas.google.com/g/2005#kind"',
' term="http://schemas.google.com/docs/2007#document"/>',
'<title>', titleDoc, '</title>',
'</entry>'].join('');
xhr.open('POST', URI , true);
xhr.setRequestHeader('Content-type', 'application/atom+xml');
//xhr.setRequestHeader('GData-Version', '3.0');
xhr.setRequestHeader('X-Upload-Content-Length', '0');
xhr.setRequestHeader('Authorization', 'OAuth ' + google.getAccessToken());
xhr.send(atom);
This is the request/response packet from the servers
Request URL:https://docs.google.com/feeds/upload/create-session/default/private/full
Request Method:POST
Status Code:400 Bad Request
Request Payload
<?xml version='1.0' encoding='UTF-8'?><entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007"><category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document"/><title>test</title></entry>
Response Headersview source
cache-control:no-cache, no-store, must-revalidate
content-length:19
content-type:text/html; charset=UTF-8
date:Sun, 01 Jul 2012 06:46:21 GMT
expires:Fri, 01 Jan 1990 00:00:00 GMT
pragma:no-cache
server:HTTP Upload Server Built on Jun 14 2012 02:12:09 (1339665129)
status:400 Bad Request
version:HTTP/1.1
The repose with gdata Version uncommented, but this still does not create a doc in the google docs
HTTP/1.1 200 OK
status: 200 OK
version: HTTP/1.1
cache-control: no-cache, no-store, must-revalidate
content-length: 0
content-type: text/html; charset=UTF-8
date: Sun, 01 Jul 2012 21:02:16 GMT
expires: Fri, 01 Jan 1990 00:00:00 GMT
location: https://docs.google.com/feeds/upload/create-session/default/private/full?convert=false&upload_id=AEnB2UoaVeHUGhiIgKm9fL-WL_Fd1DdAAh7rdYDx6G6cseLwHgAMBfkdt42kf9YiKFJ8q9tiZ8vLVUb3Sr-KVUZi01m3vY6ZUw
pragma: no-cache
server: HTTP Upload Server Built on Jun 14 2012 02:12:09 (1339665129)
You can use simple upload to create an empty file, just replace your url with https://docs.google.com/feeds/default/private/full and uncomment the GData-Version header.
Another option (recommended) would be to use the files.insert method of the new Google Drive API instead.

Twitter API Get mentions

Im having loads of issues with the Twitter API and GET. Hopefully someone can point out my mistake of help me in the correct direction. I got the POST correct for posting statusses, but i want to get the users mentions, but Im receiving "Could not authenticate with OAuth" the whole time.
Below are all my strings and headers as I set / get it. Please help. :)
- Generate Base URL -
base=GET&http%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fmentions.xml&oauth_consumer_key%3D0RaXE4T4CuMFJHI1jViEQ%26oauth_nonce%3DDGTQVDPXRAYASJJFJLJF%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1309954505%26oauth_token%3D298006718-8yTikfcuvQ3Xq1ZGuykhkxK2wY0ZAOxcI0jesRxd%26oauth_version%3D1.0
----------------------------------
- Build Signature -
SignKey=ey75K0x7bgyI4BwwG5mn7vLVNQiyphJo9MMT8t6bj0&Syk7tpizLGSo2xvJ9Q8Y1G318eKO8QXvPGWoOpdXWw
Signature=Q844NOw7T0oq8tNQkdR/6ez6Z8s=
----------------------------------
- Request twit Start -
postvars=
url=http://api.twitter.com/1/statuses/mentions.xml
----------------------------------
- Socket Before Header Send -
GET /1/statuses/mentions.xml HTTP/1.0
Accept: */*
Referer: http://eden.fm
User-Agent: Mozilla/4.0 (compatible; ICS)
Host: api.twitter.com
Authorization: OAuth oauth_nonce="DGTQVDPXRAYASJJFJLJF", oauth_callback="oob", oauth_token="298006718-8yTikfcuvQ3Xq1ZGuykhkxK2wY0ZAOxcI0jesRxd", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1309954505", oauth_consumer_key="0RaXE4T4CuMFJHI1jViEQ", oauth_signature="Q844NOw7T0oq8tNQkdR%2F6ez6Z8s%3D", oauth_version="1.0"
----------------------------------
- Socket Header End -
HTTP/1.1 401 Unauthorized
Date: Wed, 06 Jul 2011 12:16:11 GMT
Server: hi
Status: 401 Unauthorized
WWW-Authenticate: OAuth realm="http://api.twitter.com"
X-Runtime: 0.00899
Content-Type: application/xml; charset=utf-8
Content-Length: 152
Cache-Control: no-cache, max-age=1800
Set-Cookie: k=41.133.180.120.1309954571265496; path=/; expires=Wed, 13-Jul-11 12:16:11 GMT; domain=.twitter.com
Set-Cookie: guest_id=v1%3A130995457172572573; domain=.twitter.com; path=/; expires=Sat, 06 Jul 2013 00:16:11 GMT
Set-Cookie: original_referer=ojItV1ByhTzWh74Jc1NQEw%3D%3D; path=/
Set-Cookie: _twitter_sess=BAh7CDoPY3JlYXRlZF9hdGwrCNR9YP8wAToHaWQiJTQzZGVmMTE3YTI5ZjEz%250AOGYzZWEwYjlmNTRlM2I3MzA2IgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVy%250AOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--dd24ddb28d1207c2ebf479e57b6f9edb82553bbe; domain=.twitter.com; path=/; HttpOnly
Expires: Wed, 06 Jul 2011 12:46:11 GMT
Vary: Accept-Encoding
Connection: close
----------------------------------
- Request Done Socket DocEnd -
result=
status code=401
headers=HTTP/1.1 401 Unauthorized
Date: Wed, 06 Jul 2011 12:16:11 GMT
Server: hi
Status: 401 Unauthorized
WWW-Authenticate: OAuth realm="http://api.twitter.com"
X-Runtime: 0.00899
Content-Type: application/xml; charset=utf-8
Content-Length: 152
Cache-Control: no-cache, max-age=1800
Set-Cookie: k=41.133.180.120.1309954571265496; path=/; expires=Wed, 13-Jul-11 12:16:11 GMT; domain=.twitter.com
Set-Cookie: guest_id=v1%3A130995457172572573; domain=.twitter.com; path=/; expires=Sat, 06 Jul 2013 00:16:11 GMT
Set-Cookie: original_referer=ojItV1ByhTzWh74Jc1NQEw%3D%3D; path=/
Set-Cookie: _twitter_sess=BAh7CDoPY3JlYXRlZF9hdGwrCNR9YP8wAToHaWQiJTQzZGVmMTE3YTI5ZjEz%250AOGYzZWEwYjlmNTRlM2I3MzA2IgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVy%250AOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--dd24ddb28d1207c2ebf479e57b6f9edb82553bbe; domain=.twitter.com; path=/; HttpOnly
Expires: Wed, 06 Jul 2011 12:46:11 GMT
Vary: Accept-Encoding
Connection: close
----------------------------------
result=<?xml version="1.0" encoding="UTF-8"?>
<hash>
<error>Could not authenticate with OAuth.</error>
<request>/1/statuses/mentions.xml</request>
</hash>
Why not take a look at my open source TTwitter library? Even though this version of the project is now depreciated (I've rolled TTwitter into a larger project to develop more social networking components) it'll still point you in the right direction :)

BlackBerry Browser (4.5) refuses to cache CSS. Is there a workaround?

I develop an internal web application for my company. It is used by our field technicians, all of whom carry a BlackBerry 8330 running 4.5. I would consider myself fortunate to have such a consistent target platform, if it wasn't BB 4.5...
I've noticed a lot of request overhead in loading the site, and know that if only my CSS resources were cached, the load time would be cut dramatically. The BB always requests a full copy of the CSS file, no matter if the Expires, Cache-Control, or Last-Modified headers are set. It doesn't hit its cache, it doesn't send an If-Modified-Since, nothing.
Anyone run into this or know what I can do to workaround it? I'd really like to avoid inlining my CSS if I don't have to.
EDIT: I just noticed that it is always requesting the page twice. Below are diffs between to 2 requests
GET /css/bb.css HTTP/1.1 |GET /css/bb.css HTTP/1.1
User-Agent: BlackBerry8330/4.5.0.77|User-Agent: BlackBerry8330/4.5.0.77
profile: http://www.blackberry.net/|profile: http://www.blackberry.net/
-----------------------------------|Accept: application/vnd.rim.html,te
-----------------------------------|Connection: close
Referer: http://10.7.2.167/page.php|Referer: http://10.7.2.167/page.php
-----------------------------------|Accept-Charset: ISO-8859-1,UTF-8,US
Host: 10.7.2.167 |Host: 10.7.2.167
-----------------------------------|Accept-Language: en-US,en;q=0.5
-----------------------------------|x-wap-profile: "http://www.blackber
Cookie: PHPSESSID=xxxxxxxx; token=x|Cookie: PHPSESSID=xxxxxxxx; token=x
-----------------------------------|Via: MDS_5.0.0.86
|
HTTP/1.1 200 OK |HTTP/1.1 200 OK
Date: Sun, 05 Sep 2010 09:34:52 GMT|Date: Sun, 05 Sep 2010 09:34:54 GMT
Server: Apache/2.2.15 (Debian) |Server: Apache/2.2.15 (Debian)
Last-Modified: Sat, 04 Sep 2010 02:|Last-Modified: Sat, 04 Sep 2010 02:
ETag: "10426-d64-48f65ab39bf80" |ETag: "10426-d64-48f65ab39bf80"
Accept-Ranges: bytes |Accept-Ranges: bytes
Content-Length: 3428 |Content-Length: 3428
Cache-Control: max-age=12960000 |Cache-Control: max-age=12960000
Expires: Wed, 02 Feb 2011 09:34:52 |Expires: Wed, 02 Feb 2011 09:34:54
Vary: Accept-Encoding |Vary: Accept-Encoding
-----------------------------------|Connection: close
Content-Type: text/css |Content-Type: text/css

Resources