« Yahoo! India launches a job search website | Main | How to get URL query-string variables within Flex application »

March 03, 2006

HTTP Authentication for HTTP/GET requests using ActionScript 3

I am working on ActionScript3 API for Bloglines services, which requires HTTP Authentication for its two of the services. I was not able to set the header of a HTTP/GET request. Macromedia Flash Player allows you set the header only for POST requests. I discussed this issues with Ted Patrick and he told me how I can us Socket to achieve the desired and he was very kind to give a me code-snippet, which got me started. Thanks Ted.

Finally, I could implement a class(HTTPURLLoader) which allows me to:

It basically connects to a HTTP server on port 80(hardcoded for now) and sends an HTTP/1.0 request so that server closes the connection immediately after response. I could use HTTP/1.1 to keep connection alive and do things. But then closing connection would require some more logic, either a timeout logic if there is no activity on socket then close the connection, or find the end delimiter of response and then close. So I chose the easiest approach :)

I am still working on it and there is a lot(bugs-fixing, optimization, code-commenting, removing hardcoded stuff etc) to be done. I just wanted to share whatever I have done so far. I think, idea is more important than the implementation.
Anyways, I also implemented Base64 in AS3 and also OPML parser for Bloglines. I would soon upload the entire Bloglines AS3 API source.

Download the code:

Usage:-

<mx:Application xmlns:mx="http://www.macromedia.com/2005/mxml" creationComplete="onAppInit()">
<mx:Script>
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
import com.abdulqabiz.net.HTTPURLLoader;
import com.abdulqabiz.crypto.Base64;
private var loader:HTTPURLLoader;
private var END_POINT:String = "http://rpc.bloglines.com/";
//you need to set your email/password required for Bloglines access.
private var email:String = "YOUR_EMAIL_FOR_BLOGLINES";
private var password:String = "YOUR_BLOGLINES_PASSWORD";
private function onAppInit()
{
loader = new HTTPURLLoader();
loader.addEventListener("complete", onComplete);
loader.addEventListener("httpStatus", onHTTPStatus);
loader.addEventListener("progress", onProgress);
//for simplicity,not handling following three events.
//loader.addEventListener("close", onClose);
//loader.addEventListener("ioError", onIOError);
//loader.addEventListener("securityError",onSecurityError);
}
private function onComplete(event:Event)
{
//headers stroed as name-value(hash map)
var rh:Object = HTTPURLLoader(event.target).responseHeaders;
var str:String = "";
for(var p:String in rh) str+= p + ":" + rh[p] + "\n";
console.text+="Response Headers: \n" + str + "\n\n";
//data property holds the content
console.text+="Body Content:\n" + HTTPURLLoader(event.target).data + "\n\n";
}
private function onProgress(event:ProgressEvent)
{
//bytesTotal is not accurate, and its 0 if server doesn't send Content-Length header.
console.text+= "Event: progress:-\n" + "bytesLoaded: " + event.bytesLoaded + "\n\n";
}
private function onHTTPStatus(event:HTTPStatusEvent)
{
//if httpStatus is 401, 403, 404, 500, 501, socket is closed.
console.text+= "Event: httpStatus (" + event.status + ")\n\n";
}
private function loadURL()
{
var request:URLRequest = new URLRequest();
//call listsubs method of Bloglines
request.url = END_POINT + "listsubs";
var credentials:String = Base64.encode(email + ":" + password);
//create HTTP Auth request header
var authHeader:URLRequestHeader = new URLRequestHeader("Authorization","Basic " + credentials);
//add the header to request
request.requestHeaders.push(authHeader);
//make the request.
loader.load(request);
}
</mx:Script>
<mx:Button label="Load URL" click="loadURL()"/>
<mx:TextArea id="console" width="100%" height="100%"/>
</mx:Application>

Posted by Abdul Qabiz at March 3, 2006 07:48 PM

Comments

Code error: "falsh" should be "flash" on line 4

Posted by: Just me at March 17, 2006 07:56 AM

Thanks dude. Fixed....

The .as file for download was fine, it was typo while writing post :)

Thanks again..

-abdul

Posted by: Abdul Qabiz at March 17, 2006 08:25 PM

cool blog

Posted by: alex at March 22, 2006 03:33 PM

Hello,

I have a camera accesible worldwide like this:


http://ip_address:port_number/CGI_script?url_params

but it's web console as well as it's images are only accesible via HTTP BASIC AUTH. This is a problem because I want to make a SWF that given the username, password and url can login and control this camera. The tricky part is the CGI that returns a:


Content-type: multipart/x-mixed-replace;
boundary=--myboundary --myboundary
Content-type: image/jpeg

I don't know how you call this - motion or streaming JPEG - but basically the CGI returns one JPEG concatenated to another and separated by a boundary. Parsing that JPEG with AS is problem #2 really. Problem #1 is looking for a way to HTTP authenticate with Actionscript 2.0 - is this possible?

I already have made a PHP that HTTP autheticates and returns one frame of the JPEG and I can reload this every second or so in the SWF. The problem is this demands bandwidth from the server where the SWF resides rather than using the cameras own server ro feed the SWF with images as well as beign less efficient.

The reason I'm picking your brain about this is (sorry!) that I only found a solution remotely close to the one I'm looking for in your blog (pity it's for AS 3.0). If you could point me in the right direction I would be forever grateful. Thanks.

Posted by: Serg @ Costa Rica at March 27, 2006 03:53 AM

Hi, Serg

I can't think of a solution in AS 2.0. You can not manipulate binary data in AS2. Where AS3.0, you can actually do what you are looking for.

I understand your point, polling every second probably takes lots of bandwidth...

I would surely think over this, if I come across some idea, I would share with you.

-abdul

Posted by: Abdul Qabiz at March 28, 2006 01:31 AM

Hi Abdul,

I apologize for this being kind of random, but I'm looking for some really good Flash Action Script Developers for a rich media-based start-up. I was wondering if you or anyone else is interested and is very proficient in Action Script and possibly Flex or Laszlo, to please send me an email at phils411@yahoo.com

Thanks,

Phil

Posted by: Phil Anderson at May 24, 2006 01:12 PM

Hi Abdul,
I am looking at a similar problem with slightly different twist. It is best described by a question posted here http://192.150.14.120/cfusion/webforums/forum/messageview.cfm?catid=582&threadid=1160651&enterthread=y

"I would like a standalone Flex 2.0 SWF to be able to use a set of 3rd party webservices protected by basic authentication. Is it possible? If yes, could someone put a simple step-by-step example up? I just can't see anyway to do this from the livedocs entry."

The stuff livedocs and other places seem to imply a Flex or CF server in the back-end.

What you have could be used to address this but I am not able to get it to work with the WebService object. I am using your code to do basic HTTP authentication then invoke calls using the WebService object. Though the authentication suceeds I still get prompted for user/password when I make the WebService call.

Posted by: ajit parthan at August 19, 2006 01:30 AM

Hi,

I'm looking to connect to a web service that requires authentication. In order to authenticate, I need to pass an authentication token in the HTTP Request in the web service (Authentication: "Basic token_goes_here").

Has anyone ever done this before in ActionScript? I am totally puzzled! Help would be greatly appreciated.

-phil

Posted by: Phil at December 14, 2006 08:44 AM

@phil - If you are doing HTTP post from Flash Player you can use following:-

Flash Player 7/8:

public addRequestHeader(header:Object, headerValue:String) : Void

Above method is available for XML and LoadVars objects


Flash Player 9:-

Check out these classes: URLRequestHeader, URLRequest, URLLoader...


If you are making HTTP/GET request and wanna send custom headers as part of request, you can follow the technique mentioned in the POST, it would only work for Flash Player 9 onwards...


BTW! Just looking at your comment again, I believe you are trying to bypass the HTTP Authentication to get access to WebService, if that is the case and you are targetting Flash Player 9, you can use the logic mentioned above (my post)...


Hope that helps..

-abdul

Posted by: Abdul Qabiz at December 14, 2006 02:08 PM

Actually, AFAIK we can modify the header of GET request made by HTTPService by altering "headers" property.
I saw Peter Farland advising on this subject here and I will test this inside my application in a matter of days.

http://www.mail-archive.com/flexcoders@yahoogroups.com/msg48101.html

Please correct me, if I am wrong.

Posted by: JabbyPanda at December 19, 2006 04:09 AM

@Jabby - It might have been fixed, when I wrote this code it was not there. I did good investigation, even talked to Flash Player team..

If it's there then it's good. HTTPService (without proxy) used URLRequest (URLRequestHeader etc), so this thing should be straight forward no need of my code...

Cool..

-abdul

Posted by: Abdul Qabiz at December 19, 2006 11:24 AM

There is an undocumented base64 encoder in as3 under mx.utils.base64Encoder (also base64Decoder). does anyone know the difference between drain() and flush()?

Posted by: Markas Read at December 20, 2006 06:06 PM

@Markas - I heard from someone that there is undocumented Base64 but wasn't sure where it was. I even asked someone in Adobe, but he was not also sure.

Anyways, it's always to good to see such classes part of frameworks, saves time and lets us focus on main logic.

Thanks for your comment, it's helpful.

-abdul

Posted by: Abdul Qabiz at December 20, 2006 07:16 PM

Hi All,

I have built a Flex front end that uses the webservice tag to communcate with an asp.net web service. The webservice works great and the app is simple amazing. My problem is that I want to use basic authentication to obtain the WSDL and make subsequent calls to the service's methods. I tried setRemoteCredentials and setCredentials from within Flex on the webservice but neither work. Has anybody successfully called a webservice using basic authentication without a user name and password pop-up (its hard coded for now)? I have one generic user name and password setup to call the webservice over SSL. This is used for all users. I basically want to make the communication transparent to the user and still keep the webservice secure. any ideas? Thanks! -Steve

Posted by: Steve at February 14, 2007 08:43 PM

@Steve - You can do one thing. You can use the technique mentioned (above) in this post to establish connection (authenticate) before calling loadWSDL (..) method of WebService.

I believe, once HTTP Authentication session is established before the Webservice call, you would not be asked to validate in entire session?

You can try loading WSDL using HTTPURLLoader (above). Later you can use WebService...

Hope that works

-abdul

Posted by: Abdul Qabiz at February 19, 2007 08:33 PM

Hi,

I am going to put a new version soon. That fixes some issues and more optimized. I am also looking into possibility to invoke more HTTP methods (PUT, HEAD etc)...

Posted by: Abdul Qabiz at March 1, 2007 12:24 AM

Abdul,

This looks really cool. It's perfect for a RoR project I'm working on. I'm anxious to see the updated code!

Thanks.

Posted by: Matt Lins at March 3, 2007 10:34 PM

This code looks really promising. I am actually a Flash noob, but a javascript guru ;) XMLHttpRequest (many call it AJAX) is implemented in many browsers, but plenty lack the option of authentication. That's why I am looking around in Flash land.



Basic authentication, though, sends username and password in plaintext over the wire. I use Digest authentication for that reason. I wrote an entire PHP class to tackle that on server-side. If you want I can send info on the protocol so maybe you can fix some of the Flash part? Would make me really happy :D

Posted by: Paul at April 3, 2007 08:04 PM

@Paul: Thanks, I would love to see your code. I can add this feature in this class. I am working on it to add many new features (support for more HTTP methods HEAD/PUT etc, http-status (redirection handling etc)..

Thanks

-abdul

Posted by: Abdul Qabiz at April 3, 2007 08:52 PM

How do I get this to work with an https URL?
I keep getting:
Error #2044: Unhandled ioError:. text=Error #2031: Socket Error. URL: https://MYURL

Posted by: Jeremy at April 6, 2007 02:13 AM

@Jeremy: Currently there is no support for HTTPS. I am basically creating Socket connection over port 80. For HTTPS, I have to implement HTTP over TLS.

I want to add all features in my libraries it's just I am always busy with something at my full time job :)

However, I would check it out..

Thanks for your feedback.
-abdul

Posted by: Abdul Qabiz at April 6, 2007 07:04 PM

Would it be possible to use the ideas from this class to write a replacement for HTTPService that didn't suffer from these limitations:

http://tech.groups.yahoo.com/group/flexcoders/message/54976


e.g. a class which could connect to any HTTP server and execute GET, POST, PUT and DELETE requests. I am building something at the moment which interacts with a RoR powered web service which requires this functionality. I currently have it working through a PHP proxy but it seems a little dirty...


Thanks for your work on this,


Kelvin :)

Posted by: Kelvin Luck at April 27, 2007 05:17 PM

@Kevin: Thanks for your comment. I am not sure if HTTPService without Proxy can set headers for a HTTP GET because it uses URLLoader internally, AFAIK.

I think, HTTPURLLoader can be used for other HTTP methods (HEAD, PUT etc). That's something I am working on but I am busy at my fulltime job also it's taking more time.

It would be great, if you or someone can investigate this. I have created a Google Project "as3httpclient" for these things. Where we can create different classes for dealing things which Flash Player cant.

Since I am using Binary Socket here, it's totally feasible to do anything as long as we are able to implement HTTP/HTTPS protocol spec(rfcs).

Please look at it. Please feel free to let me know your thoughts/inputs either here or you can use project mailinglist or my email (mail at abdulqabiz.com), whichever is comfortable to you...

Project: http://code.google.com/p/as3httpclient/
Blog post: http://www.abdulqabiz.com/blog/archives/flash_and_actionscript/actionscript_3_httpc.php

Thanks

-abdul

Posted by: Abdul Qabiz at April 28, 2007 01:46 AM

Hi Abdul,

Would your as3httpclient/HTTPURLLoader code work with a Flash CS3 created SWF?

I'm trying to implement your HTTPURLLoader code in Flash CS3 for Flash 9 player. I'm trying to build a SWF that would communicate with a REST service. Conceivably, it would do a POST to a REST service for authentication and it would receive tokens in the response headers and all subsequent calls to the service would send that token in the header of the GETs.

I've been trying to implement this but with no luck. I've noticed a lot of subtle inconsistencies between Apollo and CS3 Actionscript3.

For example Apollo's HTTPStatusEvent supports responseHeaders but the Flex/CS3 version does not.

Do you know if it's even possible to do the RESTful communication with a CS3/Flash9 actionscript 3 SWF? Or would this work for Apollo only?

Posted by: pinder at May 3, 2007 01:13 PM

@pinder:

> Would your as3httpclient/HTTPURLLoader code work
> with a Flash CS3 created SWF?
Yup! It's written in ActionScript 3, so it would work for Flash Player 9, no matter what tool you use to compile your app. In this case, it's Flash CS3.

> Conceivably, it would do a POST to a REST
> service for authentication and it would receive
> tokens in the response headers and all
> subsequent calls to the service would send that
> token in the header of the GETs.

You can use URLLoader for authentication. For later calls, you can use HTTPURLLoader. I am working on a new version of HTTPURLLoader, that would allow you to do POST also. If you want to use HTTPURLLoader for POST, you can look into code and remove the hardcoded "GET" to request.method..

> I've been trying to implement this but with no
> luck. I've noticed a lot of subtle
> inconsistencies between Apollo and CS3
> Actionscript3.
I have not yet used Flash CS3, but I can imagine there might be difference in flex framework but you should be able to use Flash Player 9 APIs...

> For example Apollo's HTTPStatusEvent supports
> responseHeaders but the Flex/CS3 version does
> not.

Apollo has better APIs for flash.net.* classes.

> Do you know if it's even possible to do the
> RESTful communication with a CS3/Flash9
> actionscript 3 SWF? Or would this work for
> Apollo only?

Yeah, without any problem. For REST, you have to just use URLLoader and related classes for REST...


Posted by: Abdul Qabiz at May 3, 2007 11:35 PM

Very cool, but you need to rig the backend server to handle XMLSocket in order to connect to port 80 from flash.

Really limits the use of this unfortunately. I wish Adobe would give us port 80 access via regular crossdomain xml

Posted by: blaze at May 11, 2007 05:41 AM

Would it be possible to use this to upload a ByteArray? Would love to be able to upload an Image as ByteArray over HTTP without having to Base64.encode/decode

Posted by: Guojian at May 20, 2007 03:15 AM

@Blaze

Yes, that would be possible. I currently have an example that uploads a file using this method including authentication on another then the default port.


Abdul,

I've have taken your idea and written my own class. This class supports other ports, aithentication, get / set and multipart messages. If you are interested in this, please let me know.


Greetz EE

Posted by: Erik at May 26, 2007 05:29 AM

@Eric: Sure, would love to look at it, if you are interested you can contribute it to as3httpclient Google project. In any-case, you can email to me at [mail at abdulqabiz.com]

Thanks

-abdul

Posted by: Abdul Qabiz at May 26, 2007 04:26 PM

I want to read the http response from a urlrequest, so that I can handle the errors in a more customized manner. your article on " HTTP Authentication for HTTP/GET requests using ActionScript 3" was really nice. HTTPURLLOader doesn't comes along with flex as a component or a property, so how will I be able to use it

Posted by: saravanan at June 19, 2007 09:59 PM

Thanks! This is just the sort of thing I've been looking for.

Posted by: Jonathan Franzone at August 31, 2007 02:20 AM

Hello,

Your script worked for me. But even when I got authenticated, It shows a popup asking for password.
How can we get rid of it?

Is it hard coded in the binary flash file?

Posted by: Thiago at November 8, 2007 06:24 PM

Hi Abdul,

Just wondering if you had a newer version than the one you posted to Google groups.
Great job, btw.



Casp

Posted by: Caspar Harmer at November 9, 2007 06:39 AM

I really want to download your code, but the ZIP file just appears empty!

I can't believe how hard it has been trying to find an answer to this...

Posted by: David Bates at November 29, 2007 08:28 PM

I've got the code and been playing with it, but I can't get it to work with mx:WebServices. Has anybody got this work? Are there any examples?

Cheers,

David.

Posted by: David Bates at December 3, 2007 05:26 PM

Is your component can read headers httpS (with ssl). We just need to read the code response and the cookies names and values.
Thank you very much.

Posted by: tcherkezian at January 14, 2008 08:17 PM

@tcherkezian: No it doesn't support SSL...I have been thinking to add it...

-abdul

Posted by: Abdul Qabiz at January 14, 2008 09:40 PM

any luck with the https portion of your library. I would be willing to help build out this portion if you've started or have a plan

Posted by: Jeremy at February 4, 2008 11:42 PM

Do you have any ideas why this is not working with HTTP 1.1? The socket receives the request and returns the response, but does not close the socket. It hangs for a 5 seconds before the connection is just closed. I tried different variations of the end bytes (2 lines) but nothing seems to work and I can't find anything in the specs.

Posted by: ebaggg at April 8, 2008 02:43 AM

whats a url please tell me

Posted by: cody karpf at April 20, 2008 02:34 AM

I'm trying to connect to a service endpoint that requires HTTP Basic Auth.

The Flex library implements setCredentials() on HTTPService as unsupported, for reasons I don't really grok.

After much digging, I tried the technique discussed in this blog posting, but with no success.

After tracing through the Flex HTTP service stack, I finally realized that I could simply do the following in my initialization code before making a call on my service object:

...
addAuthHeader(myservice, "user", "pass");
...

private function addAuthHeader(serv:*, username:String, password:String):void
{
//add the header to request
var encoder : Base64Encoder = new mx.utils.Base64Encoder();
encoder.encode(username + ":" + password);
serv.headers["Authorization"] = "Basic " + encoder.toString();
}

Works fine for direct, authenticated, access from my Flex 3 app to my backend service without any need for BlazeDS or other middleman proxy strategy.

Works whether I'm using http: or https: to access the service.

Hopefully, this comment will help others.

Posted by: Brett Adam at June 11, 2008 11:28 AM

Post a comment




Remember Me?


Please enter the security code you see here

(you may use HTML tags for style)