 Michael Bly and I'm here today to talk to you about cross-origin resource sharing and why something that's really simple to implement, really simple to use both on the Ruby and the browser side, can actually have some pretty important ramifications for web app development. So a little bit of background on me, I am the co-founder and CEO of DivShot. DivShot is an interface builder for web applications. So basically we're letting you drag and drop build using Twitter Bootstrap components for now, what we're going to expand beyond that and sort of the difference from every other drag and drop tool you've ever seen is that our prime directive and our focus is on exporting clean code so you can actually, you know, use it. You may have also seen some of my work, I'm also a fellow at Intridia, I've worked on open source projects there for the last five years including Omni-Auth and Grape and yeah, it's a Ruby consultancy, fantastic people. So that's a little bit of background on me. And if you'd like to follow along with the slides, they are just, it's HTML so you can go follow mbligh.github.com slash course talk. Feel free. All right, so cross-origin resource sharing. What this basically is, if you're not familiar, actually let's do a quick poll to get this out of the way. Who's familiar with what cross-origin resource sharing is already? Okay, a good number of you. Who has used cross-origin resource sharing in either a side project or something, production, whatever? Okay, good to know. So for those of you who aren't familiar with it, cross-origin resource sharing is effectively cross-domain Ajax. So everyone's familiar with using XML HTTP requests in the browser in order to request resources from the server without having to refresh the page. Well, cross-origin resource sharing lets you do that same thing but rather than being restricted to the same domain that the page loads on, which has been the traditional browser security case, now you're able to request from other domains as long as on the server side they're implementing this protocol. So you might be familiar with JSONP as well where basically you make a request to a remote endpoint that wraps it in a callback function that is then executed as JavaScript on your side and JSONP is effectively a hack way to do cross-domain Ajax. It only works for get requests. You don't really have any kind of error tracking, error reporting, custom headers. There's lots of things you can't do with JSONP that you can do with cores. And like all good things, cores doesn't work that great in IE less than 10. There is an IE equivalent of the cores called X domain request. There are also some various restrictions on how that works as opposed to the full cores standard. I'm not going to get into that now, but if you're building something that's for IE 8 and 9, there are a lot of things that I'm going to talk about that you'll be able to do, some that you won't, so dig into that a little bit more. So what is important about cores? Why does this cross-domain Ajax actually matter when it comes to building web applications? What it allows us to do really for the first time is we can build an application that effectively implements service-oriented architecture on the browser side. So there's actually been a lot of talk about SOA at RubyConf today, and I think that's because more and more as we mature, as our applications get larger, you realize that having this big monolithic application just becomes more and more unwieldy, whether that's because your tests are taking longer and longer to run, whether that's because you have completely unrelated code and just everything's getting out of control. The more you can break your app apart, the more you can turn it into small modules, small independent things that work together to give you the whole package, the better off you are. So to sort of go over the, oh, and the other thing that I'm going to go to in a little while is that if you build a public API for your application and you allow those developers to use cores, that can do some really amazing things, and that's one of the things that I'd say if there's going to be a takeaway of go do this, if you have a public API for your application, figure out how you can make it work with cores because there's some really awesome things, but we'll get back to that in a little bit. So what is cores? Cores is basically just a protocol where browsers and servers have agreed on a set of headers that basically tell you whether or not a given domain is allowed to make AJAX request to it. So basically how this works is if you're doing a GET request, and it's just a vanilla GET request, you don't have any custom headers you need to send or anything like that, your browser will just send that GET request over to the server, and the server has the option to respond with an access control allow origin header. And the access control allow origin header basically just says whether or not the origin domain, so if I'm on app.myapp.com and I'm making a request to API.myapp.com, then API.myapp.com has the opportunity to either approve or deny that origin of app.myapp.com for this request. So basically in the response headers, there will be access control allow origin, and that can be a star, which just means any domain can make a request at any time, or that will be a specific origin. So if it's a specific origin, that's either something that's going to be just statically added to your server somewhere in that I'm only ever going to allow requests from this one, or you could dynamically compute what that's going to be and send back a domain if it matches some whitelist or some other specification. So that's how it works for a GET request. For a post or put or delete, or if you need to send custom headers, then what happens is it sends an options pre-flight request. So what the browser does is it says, okay, you're trying to make an Ajax request across domains and it's not a vanilla GET request. I need to know more than just if this is allowed, because posting data to the server could be dangerous in certain scenarios, and the entire reason that browsers weren't allowed to do this before and the entire reason that cores exist as a standard is to basically protect servers from cross-domain site attacks. So, you know, cross-site, you know, that's sort of along similar principles as cross-site forgery protection and things like that, by not allowing Ajax to go across domains, you enable better security by default. So if you're making any request other than a vanilla GET request, then this options pre-flight request is sent first. So the browser, before it actually sends the post or whatever you're trying to do, it'll send an options request that's basically saying, you know, hey, server, I want to make this request. Is that okay? And the server will then respond with these various headers, one of which is the access control allow origin, which I already talked about a little bit. Another is access control allow methods, and this can be comma separated. So if I have the same endpoint and it can respond to GET, POST, PUT, DELETE, then I would add all of those to the access control allow methods in that options pre-flight request. There's access control expose headers and allow headers. So expose headers is saying, these are the headers that I'm going to send that I want the browser to be able to see. There are some basic headers that are that it's always allowed to see, but if you have any kind of custom headers that you're implementing things like that, maybe you're sending an API rate limit along as a header, you would need to add that to the expose headers. There's also the allowed headers, which is this, these are the headers that the browser is allowed to send to the server. So by the same token, if I don't specify certain headers that I'm expecting, then the browser is actually going to strip those headers off of the XML HTTP request before it's sent. So the server never actually sees that unless it gets the okay. And again, this is all done for security sake. And this brings us back to SOA in the browser. So this is sort of the really generic idea of what is SOA. You know, in a traditional application, you might have a monolithic, say it's a Rails app, doesn't really matter what it is. And that incorporates all of the different aspects of your application. You know, if you have authentication, user messaging, and activity feed, profiles, you know, a public API that developers can access. If that's all in a monolithic application, then, you know, that's a single point that the browser is communicating with. And that may be a request response cycle, or that may be through Ajax, you know, something more responsive like that. But either way, basically, you're just communicating with one endpoint. If you take the service-oriented approach, then you take each of these components of your application. So your authentication, your API, your messaging system. And you break those out into independent services. And by independent services, that means, I mean, it can mean a variety of things. That can mean basically that they're logically separate even if they're on the same server. So you're just basically separating all that logic, these existed different endpoints, or they can be, you know, entirely different languages, entirely different run times, different server infrastructure, different everything. And what this does is it gives you a ton of flexibility. So the advantage of the advantages of a service-oriented approach is that you have scalability that works better because each of these individual service parts can be scaled independently because, theoretically, they can all be on different infrastructure. So if I have an application and 90% of my requests have to do with user messaging and only 10% have to do with everything else, it would be really nice if I could, rather than scaling up this, you know, giant monolithic app that maybe has a big memory footprint, has a long startup time, what if I could just scale up the messaging part and have 10 times as many messaging servers running as I have everything else? So that's the basic idea behind the scalability of a service-oriented design. Reusability, which I completely misspelled. Reusability is also important because as you build these as independent services, you might come across, say, you're building another application that can actually utilize the same service. These services can kind of take on a life of its own. If you're familiar with Heroku add-ons, in a lot of ways, once you start building with a service- oriented approach, it's almost like you're creating your own add-ons for your application that do a specific purpose that you need. And if you have another application that has that same need down the road, then you're able to reuse that service without a lot of work, without stripping out a bunch of code. Again, flexibility. This just allows you, you know, maybe I have parts of my application that are very non-concurrent real-time focused, and so I feel like Node.js is a better fit for that part of the app. But for my main application and my API, I just want to use Ruby because I've already got code in there, and it's really simple and everything like that. So it allows you to implement things in different architectures without sort of sacrificing or coming up with complex schemes. Fault tolerance. So if I have part of my site go down, if I have built a service-oriented architecture that's performing well, it's potential that I only have a partial outage of my site rather than it taking down the entire thing. And clean boundaries is just saying that because these services are built independently, they're able to communicate independently, which means that there's always a clean separation of responsibilities in your code. So it forces you to make harder and more important architectural decisions earlier. You have to really think about your app in terms of these modules and these services rather than just, you know, oh, I'm going to slap some code in and we'll clean it up later. So it kind of forces better coding practices, a little more architectural thinking on you upfront, which also is a bit of a disadvantage. There is a bit of initial complexity to a service-oriented approach because now you're not just building one app. You're not just using sort of the standard path. You're building many applications. You have to figure out how and when they need to communicate with each other, how and when they need to communicate with the browser or whatever your central control point is. So there is a little bit more complexity with a service-oriented architecture. Cross-service communication can be tricky. You know, if I have a user's table on one server but I have another service that needs to know some of that user information, it can be a little bit tricky to figure out, you know, do I pull that over and cache it for a while? Do I, you know, make a request each time to that service? So figuring out the boundaries of when and how much they should communicate with each other can be tricky. And the other thing is that there's not really, at least in the Ruby world, and I'm not familiar with one that I think is particularly great. There's not, there's not sort of a framework that's like, that's built from the ground up to let's make service-oriented apps, you know, this is an easy way to do it. There's lots of sort of tutorials. There's some books out there that describe how to do it. But there's nothing that's as easy as, you know, Rails G controller, user's controller that's out there. So those are some of the disadvantages. But if you're building something that's more than a toy application, that you're expecting to spend months or even years maintaining, those disadvantages are really worth the pain to get to the point where you're thinking architecturally, you get that scalability and that modularity. So if you wanna cheat a little bit and you wanna sort of have a service-oriented architecture, but you don't really wanna break it out into, you know, I'm gonna run this on this server, I'm gonna run this on that server, you can use Rack Cascade. So, you know, if you're familiar with Rack, all Rails apps are Rack apps, all Sinatra apps are Rack apps. And so what you can actually do is in your Rackup file, you can just run a Rack Cascade of all of your applications. So say you just have, you know, a folder for each application. And what Rack Cascade does is if it encounters a 404, so it says resource not found, then it just falls through and tries to call the next application until something returns a non-404 response, or it returns a 404 response if it can't find one. So that can sort of be a cheat, where you're breaking it out into these individual services, but they're still all running in the same stack while you're sort of spinning things up. And my recommendation, if you're going service-oriented, would be to keep things lightweight. You know, I'm a huge fan of Sinatra. It's something that you can just get in so quickly, do a little bit of work, you know, everything's so clear. You know, sort of a plug for my own library, but I also built Grape, which is a stressful API framework. And these apps tend to be a little bit easier to break apart than Rails apps. Now, that's not to say that there's not likely to be a place and a case for Rails in your sort of service-oriented architecture, because you're probably going to end up having maybe a core application that runs a lot of your logic, but not some of these services, and that might make sense as a Rails app. And I'm sure that people that you may have seen, you know, there's the possibility of doing sort of one file Rails apps and breaking that apart even more. But personally, I prefer things like Sinatra. So as far as implementing cores in Ruby, it's actually dead simple because there's a gem for everything, so use the rack cores gem. So in your gem file, you just add rack-cores, and then it's a rack middleware. So in your rackup file, in an initializer for Rails, you just use rack cores. You have, you basically pass it in a loud block and that's where you specify, these are the origins that are okay. You can pass multiple arguments if you need to to that one, and then you can specify resources. And on each resource, in addition to just specifying the path, you can also specify methods, which is going to give you that access control allow methods. You can supply headers, expose. So this is just a shorthand way to automatically handle those options pre-flight requests as a rack middleware. So you just slip this into your project and you're done. So when I talked about if you have a public API looking to implement in cores, part of the reason is because it's really, really easy. So let's dig in a little bit. I built just a really simple service-oriented in the browser example so that we can go through both a few of the sort of principles of what's going on and a few of the challenges you'll run into. So here is my application. It's very simple, obviously. And first thing I need to do is I need to sign in. So now it's come back here and it asks for a status. So hello, oops, hello RubyConf. This is not my laptop and it shows. So I hit update, it shows up over there, and that's all this application does. So this is obviously very basic. This is not something that needs to be built in a service-oriented manner, but it was built in a service-oriented manner so that I could show you a few of the things that you might wanna do. We're just gonna go through the code on GitHub a little bit. So the first thing, and this is one of the things that even though it's not terribly important, I think is just really cool about what you can do with cores and that is that the app itself is just static HTML. There's no server anything going on. When you land on this page, that's just static HTML. So I could serve that using Apache. I could serve that by just dumping everything onto Amazon Cloud front and now I have it on a CDN. So that gives you just a real simple power, I think, to be able to serve your application that can do all of these amazing things as just static HTML and not even worry about the server side for your core application. So that's sort of the first thing. And if you look, basically we just have a basic HTML and all of the logic takes place in application.js. Oops. So taking a quick look at this. The first thing that I'm doing here, and this is a terrible hack that you'd wanna do better in a real application, but we need to know the different services that we're talking to. So in this case, I've built two services. I've built an authentication server, yes? Oh yeah, you bet. Let me, is that better? All right, cool. So I've built two services for this. I've built an authentication service and I've built a stream service, which is what allows me to publish and read from that stream you saw. So basically right now I'm just setting up that these are the hosts of those services that I'm going to access. So you need some way to do that usually, but this is a bad way because I'm using conditional logic and hard coded things, so don't do that. The next thing I'm doing here is I'm setting an Ajax pre-filter, so the authentication scheme that I'm using is loosely based on OAuth2 type things in that we just have a bearer token that's generated and that bearer token is given to the browser and then stored locally on the browser so that it can make subsequent requests to the stream service, excuse me, using that token. So what I'm actually doing here is I'm using JQuery, I'm using an Ajax pre-filter on JQuery to say, if I have a token, then I'm going to try to make authenticated requests when I do Ajax requests, so I'm going to add an authorization, I'm gonna add an authorization header to my request that sends along this bearer token. So the next thing that we can look at is what happens when the app launches and what happens here is that if you look at the OAuth2 specification, the way that you can send a bearer token to a client-side application, so something where you can't trust the code, you can't have things like client secrets because the end user can just inspect the code and pull it out if they need to. So the way that that's dealt with, at least somewhat, is by passing the token in the location hash. So because it's passed in the location hash, if you're not aware of this, anything after the pound sign in the URL is never actually sent to the server. So you want this token to be obfuscated at least to a degree, and by sending it in a location hash, that's not actually sent to the server when the request is made, so you have a little bit more security there. So all I'm doing is I'm checking if there's a token when in the location hash, when we launch the application, and if there is, then I'm going to verify and make sure that that's a valid token. Otherwise, we need, otherwise we already have a token, so I'm going to try and attempt to fetch the stream of updates. And now I think it'd probably be a good time to move over to our authentication app. So that was our static HTML browser app. Now our authentication app is just a one file signature app that I wrote, and here we're just setting up Redis, that's not a big deal. So the first thing you can see is all we're doing is if you go to the root of this, then we're going to authenticate using Twitter OmniAuth, and that's just because that was the simplest thing to implement. So then we go through the normal OmniAuth process if you're familiar with that, but basically it's going out, making the OAuth request, coming back, and fetching user ID, user information. So that's what's happening in this callback phase is we're just saving some user information, and then we're going to generate that access token that I talked about. So if you look at this regenerate token method, all we're doing is we're generating a URL safe token, and we are saving that in Redis, so that, excuse me, we can look it up later. And then like I said, we redirect back to the app host and include in the hash the bearer token that we just had. So that's really most of what there is to this application. The only other thing that we're doing is we have a Verify method where we're basically just checking to see if a token that's passed is associated with the user, and if it is, we're returning information about that user. And we'll get to that in just a second. Sorry about the coughing. So moving on to our stream application. This again is just a one line Sinatra application. But this can show you how you can sort of use services that talk to each other in general. So what we're doing here is we have an authenticate method. So if you go down here, I can either post to my activity stream or I can get activities from my stream. And what happens before any of that happens is I authenticate based on the token, the bearer token is posted in, is passed in. And so here what happens is I'm actually making an HTTP request to that auth server, to that Verify endpoint that I just talked about. And I'm saying, hey, I just got this token, but I'm not the auth server, I'm the stream server, so can you tell me if it's okay? And if the auth server says, yep, that's a valid token, then the stream server can go ahead and complete the request and associate things with that token and that user ID. Otherwise it will send back an unauthorized message. So this is a way that services both talk to the browser or talk to the sort of central controller, but can also talk to each other when necessary. And so if we go back to, I'm not gonna spend too much longer going through this, the code is on GitHub, but just to go through sort of how the posting works, we'll go back to application.js, you can see the Verify token happens at the beginning when we log in just to make sure that the token that we have stored is valid and then we have fetch stream and post activity. These are both just simple. And I guess that's something that I didn't mention that I definitely should. All of these requests, all of these cores requests, you do just like normal AJAX requests. So on the browser side, you don't have to do anything different. It will automatically do the options preflighting and everything like that for you. So if you're using jQuery, if you're using whatever, just do a normal XNL HTTP request and it'll go through. So long as the server is sending those appropriate headers. So we can get activities, we can post activities and then we're just updating the interface. So I mean that's pretty much it. But what you can see is that this is really pretty simple to do. And again, I really feel like it's something powerful where I have this application that's just static HTML. And I'm talking to this authentication service. But what if I had a separate application but I'm using the same user base? Well, now that application can also talk to the authentication service. And I have this stream service and maybe I have an email notification service that reads from the stream service to be able to push notifications. So once you start breaking things apart and modularizing them, then you're able to just do a lot more sort of reusing your code and thinking about things in terms of passing messages rather than just having this monolithic idea. And once you can do that in the browser, then you just have the power to load. If I have a messaging part, if you imagine something like Facebook where you have messaging up here and a user stream here and you have a photos application and all of these things, the browser can now coordinate all of those requests. They can all go to different services on different servers built with whatever the best architecture is for that. And it all just comes together nicely. So that's why I think that Cores is particularly powerful for sort of this browser based service oriented architecture approach. So I think that I just went through all of that. So we're gonna go ahead and move on and talk about public APIs that use Cores and why that's awesome. And that is probably my favorite animated GIF ever. So what's so awesome about it? First of all, it lowers the barrier to entry. So if I build an application and I allow a public Cores API, that means that the only thing that someone needs to do to be able to build an app that leverages my API is have a text editor and a browser. They don't need to run a server. They can do this locally. They can run this from file colon slash slash. So this just opens up a whole new ability to build these super lightweight apps that do a lot more than you'd expect they'd be able to. It allows you to do mashups without servers. So if you imagine all of these mashup applications where it's let's take Flickr data and mash it up with Google Maps data. Traditionally that was done by you create a server side application that accesses both of those APIs. It somehow mashes that data together and then displays it down to the browser in a way that's consumable. But if I use Cores and I just build a web page that makes Cores requests out to the Flickr servers. It makes Cores requests out to the Google Maps servers. Now I can do all of that processing on the client side. So I'm able to create powerful applications that combine multiple services that do all kinds of things without ever needing to build some kind of custom server architecture. And that's also important because when you think about things like Chrome extensions when you think about sort of simple downloadable deployable HTML that's a really powerful paradigm. Services can become public APIs. And what I mean by that is that you may build a service and at first you're using it internally but over time there may be a greater use case for it than just your own internal use. So you're actually able to expose that service to the public without doing a lot of additional work. And finally it has the same burden on you. So the same requests are being made to your servers. The only difference is that you're sending these headers back but it's much less of a burden on your developer users who are building things with your API. So this is just something that I really like a lot. So as an example of something that I've built that's sort of this Cores public API, DivShot Alloy. So in building DivShot we needed the ability to have people edit CSS for their pages but I don't like editing CSS. I haven't done plain CSS in like four years. So I wanted people to be able to use their favorite CSS preprocessor. The problem with that is that there's multiple and there's valid reasons for using all of them. So I wanted to support SAS, I wanted to support less, I wanted to support stylus. And so I built Alloy as a service to allow us to do this for DivShot but then I realized that I had built a service that was really general purpose and useful. So here's an example of it in DivShot. So I'm in my application, I have this, I'm gonna give it a class, let's say super class. Now I'm going to edit some stylus. So here's how we can utilize it in DivShot and that's great, it allows me to do custom CSS on pages which is a feature that lots of people wanted and now I was able to implement it. But what it also allowed us to do is release it as an open source public API so that anyone can use this. So if you go to divshot.com slash Alloy you can have this web API for preprocessing CSS. So whether I'm using stylus, it just compiles. I also built these book marklets that will actually let you click the book marklet and then click a text area and then if you've written sass or stylus in that text area it will just convert the content of that into CSS. So if you're using a website like Tumblr where it gives you the ability to have custom CSS but you don't really wanna write just CSS, you wanna use a preprocessor, you can now use this book marklet instead. And these were use cases that came up because I built it in this service oriented way because I built Alloy as a separate service rather than as part of a monolith. And so I think that it's just a really powerful paradigm to allow you to think about things that way. And famous examples. The GitHub API is 100% supporting of Cores which is amazing and you can see some really awesome examples of that. Things that are just hosted as static HTML on GitHub that give you ways to browse your issues, browse everything on GitHub in some kind of intuitive or new novel fashion and that's because GitHub added this Cores support. In the last few months, Amazon added Cores support to S3 and that's a huge thing because now what you're able to do by leveraging S3 and Cores, you can actually trigger file uploads that are uploading, whether it's a 20K JPEG or a 200 meg movie, you can offload all of that work onto Amazon servers and it never even has to touch yours because by using Cores, the request goes straight to Amazon so the file goes straight to Amazon and all you have to do is be able to deal with the response which is gonna be a URL of where it ended up being stored. So that's an example of what I talked about where it takes the burden off of your users and doesn't add any burden to you because either way, this file is gonna get uploaded to S3 but in this case, it was only uploaded to S3 rather than uploaded to my server which then got uploaded to S3. You know, one thing to think about when you're implementing this on a public API is how to handle authentication. Like I said, in the browser, you can't count on any kind of secret so if you have a client secret, something like that, you can't count on that being kept but you still wanna be able to identify applications so that you can remove bad actors, things like that and GitHub solution for that is that they only allow Cores requests from domains of registered OAuth applications. So if I register an OAuth application that is embli.github.com, now I can actually make Cores requests to the GitHub API from embli.github.com because I registered that application and I thought that that was a clever way to solve this problem. It still lets you identify an application so it just looks at the origin of the request and says, oh, this is coming from embli.github.com so this is Michael's fancy GitHub API application. So I just wanted to mention that as a good way to possibly handle authentication if you do build this into a public API. So now you know what you can do with Cores today and it really is a simple technology that just has a lot of applications and the question that I wanna ask because I've only just started diving into this, I think there's a whole wealth of things that you can do that I haven't even thought of yet so I wanna know what will you do with Cores tomorrow. So that's everything, I'm happy to take any questions you have and come talk to me afterwards or tomorrow or whatever but thanks for your time. Yeah. In the GitHub example, how is that any more secure? Wouldn't you still have to put the mic in the team? So it actually is less secure, I mean it sort of is less secure and there's nothing to be done about that so the reason that identifying applications is important is because if you're able to identify the application then you're able to sort of say, if this is just someone that I don't know that's just created an application maybe that gets a certain permission level whereas if it's on our own servers that gets a higher permission level because we know that it's from a trusted source so it just gives you the ability to identify but anything that's in the browser like that is sort of inherently less secure because it can be introspective at any time. But as everyone found out when the Twitter Android keys were leaked and everything like that just because it's on a different platform doesn't mean it's necessarily more secure so, yeah. How do you do graceful degradation for Internet Explorer? That is something that I don't worry about myself because DiffShot is a tool for developers and it was something that I wanted to research for the talk but wasn't able to find sort of a quick solution for so I can't answer that 100%. I know that there are some sort of shims out there and some libraries to massage, cross-domain XMLHGTB requests into that X domain object but I can't tell you sort of the best way to do it. Yeah. Why UI, which I use in my office has a module on the next ER which lets you use a native request or flash request just by configuration. Right. So you can have it work with ID. Yeah, so that's true. So sort of the way that people were doing cross-domain requests before is that flash allows you to do it as long as you have a, I think it's domain policy.xml file, something like that on the server that allows you to do it. So there's can be like a flash fallback similar to how there's a flash fallback for WebSockets, server-side events, things like that. Yeah. And you found a paradigm for integration testing with that kind of thing, right? So for integration testing, what's interesting is that because this is just standard XML HTTP requests, you can use any of the, like I can't recall them offhand, but there are various libraries for basically mocking out XML HTTP requests. And you can use those same things from the browser side. And then on the server side, that would vary depending on how you're building it. So if it's a Sinatra application, you can just use RackTest to hit it. If it's in Node.js, you'd use Jasmine or whatever you use for Node.js. But I mean, basically you test each of those independently and then you can sort of stub out the boundaries as long as you agree on a communication protocol, if that makes sense. Yeah. Can you use Chorus to authenticate for other connections like the WebSocket, for instance? That is a good question. I'm not 100% sure off the top of my head, but I believe so. Anybody else? Yeah. Okay. When you go back to do things allow top-of-the-range policy cover with the asterisk or are you always stress-as-high? With a lot of examples of asterisks, that seems like it's very important. So in my opinion, the asterisk is okay if you're talking about usually something that's like a read-only API or some kind of transient data or something like that. For anything where you're doing any kind of real authentication, something like that, then yeah, I think it's a much better policy to have specific domains that you're allowing based on however you want to whitelist that. Anybody else? So what about concerns on exploiting these? I just can't imagine like the OS in a storage, every browser running attacks everywhere. So I mean, as far as concerns, it's really no less secure than any other kinds of cookie-based session storage or things like that. Inherently, there are risks when you put data into the client. But what you can do is mitigate those risks. So in the little example application that I showed, every time it loads up the application, it verifies those tokens. You can expire those tokens say every 10 minutes or something like that and require them to be refreshed. And then you sort of minimize this window where if I forget to log out, someone can come back in, use my token and exploit that to hit the API and do all sorts of bad things. So I mean, there are definitely things that you need to watch out for. But I think in general, it's not really less secure than other ways of communicating with the backend so long as you're sort of cognizant of what you're doing and you're aware that you need to make sure that nothing that you consider to be truly secret is ever shown to the browser. All right, I think that's everything. Thank you.