Securing Vue.js with OpenID Connect and OAuth by Bobby Johnson | Armada JS 2019

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] I'm going to be talking to you about a 10 ocation and authorization in huge a us-based single page applications if you were expecting another talk you might be in the wrong room if you're not a view developer maybe you use angular or react or spelt or one of the plethora of single page application frameworks that are out there a large chunk of this talk will still be applicable to you because we're talking about OAuth and open ID Connect that sort of thing so do we have anybody that works in the identity space with us in the audience yeah ok one good so safe to say everybody else in the room is at least identity curious right ok cool and how many of you developers do we have actually using view and production ok cool very cool you should get something out of this then at least I hope so so if you have any questions please use slide o to queue them up and I will answer them at the end and if we don't get to your question don't hesitate to catch me in the hallway and ask me a question I'm happy to talk about these things also at the bottom of every slide I have a link to a page the bitly link down at the bottom that will take you to a page where you will find my slide deck including all the notes that I used to give this presentation and a github repository with the application that all the sample code was pulled out of so you can actually run that application on your local machine and see how it works at a certain point in my presentation I make a series of claims and give you recommendations these do not come from me but instead they come from various organizations focusing on those types of things so like Oh Hospital things like that you'll find links to all that documentation on that same page so don't worry about taking pictures of my slides or anything like that before I start I would like to thank the organizers and the volunteers for inviting me to my first ever visit to Serbia I've been working towards international speaking for the last year and our motto jeaious helped me achieve that goal and I'm very grateful for the opportunity if you're curious about where I'm from the u.s. is a very big place with lots of regional subcultures I typically tell people that I'm from Seattle because that's a very well-known city that most people have an idea of where it's located in the United States but I actually live about 65 kilometers south of Seattle in a city called Olympia with roughly the same population as a nova sad actually Olympia proper is about 50,000 people but Olympia is like three cities slammed together and all three cities are about 150,000 people and yes this is actually my house where I live with my wife Julia my mother-in-law Diane and a cat named Jade and my dog Louie who features prominently in my my slide deck I've lived here for about 20 years but before that I grew up in a place called green forest Arkansas which is a small farming community based in the middle of the United States with a population of about 2,000 people I was actually born though in Stockton California which is back out on the west coast but kind of Central Valley of California so I'm fairly well-traveled within the borders of my own country which is very large but I'm very happy to be visiting a place so far away from my home so thank you to the organizers for having me and thank you to all of you to come see my my talk I appreciate you so just a few more things about me I realized I'm talking about myself constantly but just to give you some of my background I'm a developer advocate engineer at an identity and access management company called office zero I run the Seattle identity and security meetup as well as the office zero online meetups the online meet up so you guys can join us if you'd like to we host them at 12 noon pacific standard time so that probably be very late for you but we do back them up a video-on-demand I like to stream on Twitch and I'm a member of the live coders dev team and I've been a software developer for about 20 years mainly kristan web development and this is me and my dog Louie hanging out in the beautiful Pacific Northwest on the schnook pass in the northern Cascades mountain range so I asked on Twitter earlier this summer what are some common reasons to roll your own authentication mechanisms and I got several responses from people and all of them of course are very wrong authentication is deceivingly simple let's talk about the problem that we're trying to trying to solve when we talk about identity the idea the idea is that you have a resource somewhere and that resource can be a capability like executing some specific process it could be a bit of sensitive data or pretty much anything else you can think of when you're using an application and you have a user somewhere that you would like to access that resource in a secure way meaning it only allows proper usage of that resource there's not only a thin ocation aspects of this transaction but there's also authorization as well firstly the problem space that we're talking about is is extremely critical if something goes wrong it goes catastrophic aliy wrong think eleven point four million euros in the event of a breach that's a career-ending mistake and this fact alone makes a ten occasion a topic that requires a lot of attention and I don't put the slide up here to scare you it's just more you need to think about it when you're dealing with this if you publish a faulty cat picture website you're not going to get fined 11 million euros but if you leak someone's information potentially gdpr lawsuit will come your way that will cost you quite a bit so you need to pay special attention when you're talking about these sorts of topics next the resources that were coming from are complex and consuming those resources are complex we exist in the world where everything is programmable just about everything has an API exposed and those resources can be accessed by a large variety of devices not only your computer but your phone your watch your thermostat I recently went to a big box store called Home Depot to buy a new refrigerator and they had several models that had the capability of being able to tweet from the refrigerator I have no idea why I'd want to be able to do that but I'm highly suspect of the security of such devices finally the accounts that we use to access these resources exist in an incredibly wide variety of sources users can come from businesses through enterprise directories users can come from social networks almost everybody in this room probably has either a Facebook or Twitter or LinkedIn account is there anybody in the room that doesn't have one of those yeah nobody at least one of us does users can come from an entirely custom solution where independent software vendors or a start-up decide to put their users in their own database with their own custom rules that sort of thing now consider the Cartesian product of all the possible devices resources and user sources and you can see why the problem can become complex very very rapidly also consider that the developers implementing these things in an organization are not typically experts in the space they have little desire to become an expert in identity and security they're primarily focused on shipping products that solve problems for their users identity is an infrastructure concern for them at best this talk was originally formatted for an hour-long time slot in an effort to stay within the time allotted to me I've cut this section from the presentation it deals with use cases that are specific standards are intended to solve well it's nice to know these things they're not critical for the topic at hand one on the plus side the link at the bottom of the slides contains the full presentation in my notes so if you're actually curious about these use cases you can review those or just catch me in a hallway and I'll talk you through them so I'm gonna skip over the identity access management use cases with that said both oo-ahh and open ID Connect use tokens as an artifact so let's talk about them and add some clarity around what they are for and how they're used in some of the some guidance about securing them access tokens are a our credentials that can be used with an application to access an API access tokens can be an opaque string a jot or non jot token its purpose is to inform the API that the bearer of this token has been granted delegated access to an API and request specific actions it's the the second statement there that I made that access tokens can be an opaque string JWT or non date JWT string is just to show you that you can't rely on being able to read the values within a access token they're not intended for you to be able to introspect into the token to derive any sort of meeting the only use for an access token is to send it to an API to authorize a request as long as the place you're sending that token to understands the token that's all the OAuth spec says about it ID tokens are a JWT token that contains identity data they are consumed by the application and used to get user information like the user's name email address and so forth typically used for UI display ID tokens conform to an industry standard from the IETF called RFC 7519 these are introspective tokens so they're just JSON formatted tokens that you can read values out of and do whatever you like with the third token type is a special token called a refresh token which contains information required to obtain a new access token or ID ID token access tokens by nature are short-lived because we want them to expire rapidly in case we leaked them somewhere a person that gains access to that access token we can take it away from them fairly easily through expiration refresh tokens on the other hand are used to get a new access token in the event you have an expired one if you've ever gone through an OAuth flow where you an application to use your profile with like Twitter or something like that and it asks you for offline access that's explicitly asking for a refresh token to where they can renew an access token without needing you to be there to click confirm right these are typically yeah I just said that offline access so a token is a very powerful artifact because the bear of a token can access your secure data first of all let's talk about storing tokens in local storage if you go and search for OAuth or open ID connect and how to use them in single page applications you'll find a lot of information encouraging you to store those tokens in local storage and this is actually bad advice there's a number of places where tokens stored in local storage become exposed to the outside world JavaScript running on any JavaScript running on the page has access to local storage so if you have a malicious script or a compromised third-party script on your page it can read local storage object and steal any of its contents on the other side of that coin any script that can access local storage can also push malicious data into local storage which can potentially make it a somewhat untrustworthy source of information imagine you're making UI decisions about granting someone access to the admin portion of your website but I can just go in and mess with local storage and still view those screens anyway finally all local storage is shared within a domain so if you have multiple applications running on the same domain using like maybe you're rewriting you have like example.com slash admin example.com slash customers and those are independent applications all of those applications can access the same local storage object they can reach and reach in and read others tokens and things like that which is a possible source of really hard to diagnose bugs from your users standpoint they just went to the customer application and it aired on them but what they're not telling you is they went to three other applications before that and had a bizarre token stored in local storage that the customer endpoint didn't understand the most common reasons we put data into local storage is for session persistence so that the user still has a token if they leave the application and come back we don't want to make them real thinik 8 all the time especially if they hit the refresh button in their browse what we can do instead of putting our tokens in local storage like what what solution can we do to get around that problem and we want to store our sensitive data in application memory so basically keeping the token in memory itself and when the user authenticates our authorization server sets our authorization server the set of endpoints for issuing tokens can set a cookie in the browser that represents the user's session to the authorization server itself this cookie is not sent to the API or anything else it's just the knowledge of the users session state with the authorization server so if we go and do something like refresh our browser and lose all of our state the application reloads and we don't have our token anymore but what we can do is use that cookie to check the session with the authorization server itself and if the users authorization server session is still valid then we can actually request a new token silently without having to prompt the user for credentials because the authorization server still knows about that user and has knowledge of them being logged in so instead of storing in local storage you just ask the authorization server do I still have a valid session and you don't have to force your user to login and your tokens stay secure in that point so there are certain flows with an OAuth that passed tokens by the ural hash of your URL and there are some inherent security risk with doing this the token is vulnerable in a number of places you have it in the redirect your old because you are redirecting the token to some other euro you're assuming is owned by that application but if that redirect URI was hijacked then you could be sending your token somewhere you weren't expecting to be that's issue one in addition it's accessible in the browser history which is also accessible by any JavaScript running on the page it's also potentially accessible in the referer header so you're under attack in a malicious pages requested right after your authentication takes place then the attacker can just look in the referer header and take your token directly out of that finally the application doesn't really know where the token is coming from it just sees it in the URL hash and it uses it so it does not necessarily have a way to verify that it's coming from a trusted source or that it was possibly injected but maliciously from somewhere else now the people that actually write authorization servers and write libraries for doing off based authorization and authentication know about these issues and they implement authentication actively to work to mitigate the risks of these sorts of things so the mitigation guidance has been around for about sevenish years for securing tokens in this way there are no new vulnerabilities that you need to worry about that have been found recently that get around the mitigation strategies that I just mentioned but as modern JavaScript and web applications evolved we re-evaluate those and recommend new practices in a few minutes I'll show you a great way to avoid all of these potential pitfalls tor you don't have to be worried about the mitigation strategies at all okay so let's take a look at the most common ooofff grant variations for web development and I'm going to start with the authorization code flow which is typically the authors of the OAuth flow that you would use for traditional server-side rendered applications and I like starting with this one because it's the most complete example of a flow it has all of the steps in it so talking about consecutive flows it's variations on this play so first we have a user and that user opens their browser and they enter a URL into their application this causes the browser to make a request to our web application and the application serves up the anonymous version of that page the user then clicks the login link in the application itself and the server the web server responds with a 302 redirect to the authorization server that redirect URL will look something like this the interesting bits here are the response type code or the response type of code that is what makes this an authorization code flow version of OAuth the browser then redirects to the authorization servers authorized endpoint which then prompts the user to login if they need to if they haven't already and/or provide consent to the Scopes that are requested through through OAuth the user logs in and grants consent the authorization server then redirects the browser back to the application with an authorization code the redirect you looks something like this the authorization code is passed as a simple query string parameter but this is not dangerous because you can't do anything with that authorization code directly you need a couple other bits of information to be able to turn that into an access token so passing it with the URL is perfectly fine this causes our browser to make a get request to our original application passing the authorization code along with it the web server then makes a post request to the OAuth token endpoint of our authorization server in this request is included the authorization code as well as the applications client ID and client secret so those are the three bits of information that are necessary to be able to turn that authorization code into an access token itself the authorization server verifies that code the client ID and the client secret and if it all checks out it responds with an ID token and access token and optionally optionally a refresh token which tokens you get depends on which scopes your request and the initial request out to the authorization server so if you are only asking for a particular audience and a permission scope you're only get a access token back if you ask for a profile you'll also get an ID token back if you ask for online access you get all three offline access you get all three the application can then store those tokens in state local to the web application itself the application then serves up the authenticated version of the page to the user passing along a session cookie that maps directly back to the state stored on the server itself single page applications work a little differently though because single page applications run in the browser themselves an untrusted client we can't send the client ID and client secret along we'd be giving away our client secrets so we have to modify the flow slightly to eliminate that that necessity and this flow is called the implicit flow and we've been using the implicit flow to authenticate single page applications for about seven years so if you've done this before you're probably very familiar with this one we still have a user that opens up their browser and enters a URL for our application which causes the browser to make a get request to our web server the web server simply serves up our entire application which has been compiled into static files and that applications loaded into the browser and runs there the web server is kind of out of the picture at that point the application running in the browser simply makes requests to the API directly so we're not going full round-trips for post backs anymore which is kind of the benefit of single page applications the spa can make direct requests for data to that API and the API responds with JSON that the application can consume in the browser to do whatever the functionality is that you're writing now when the user clicks that login button the browser makes a direct request to the authorization server directly it doesn't have a middleman in the middle to do that communication for it and this time the URL looks slightly differently instead of asking for a respond of type code we actually asked for a responce type of token directly the other values needed here are supplied at compile time and loaded into the browser with the application so the authorization server will then prompt the user just as they did before to login if they're not already logged in and to provide consent for the Scopes that have been requested the user logs in and grants consent the authorization server then redirects the user back to the browser or back to the application except this time the token is returned using the hash fragment of the of the redirected URL which our application running in the browser can then read and consume this is the scenario where I was talking about it is prone to several vulnerabilities so now let's take a look at a new flow for single page applications called the authorization code flow for proof key for code exchange we call it pixie for short this flow is very similar to what mobile developers have been doing for a few years now we are simply applying the same principles to single page applications our application is loaded into the browser just like before with the implicit flow but before we make a call to our authorization server we need to generate a couple artifacts client-side the first thing we need to do in our applications is to create a random string called a code verifier this is a high entropy random string next we're going to compute another random string from the code verifier using a hashing method that gives you something called a code challenge now when we make our request to the authorization server endpoint we send the code challenge along with it the URL has switched up a little bit the response type were back to code but we're also passing along the code challenge value along with the hashing method that we use to generate that code challenge the authorization server will then prompt the user just like before to login if they need to and give consent okay and once the user has authenticated and provided that consent the authorization server stores the the code challenge and redirects the user back to the application with the authorization code the code is sent to the browser in the hash fragment and this is fine because interception of that code is not dangerous in the same way that I described earlier once we have that code we can take both the code and the code verifier and send them to the authorization servers token endpoint and now that what we can do is we can recalculate the code challenge from that verifier on the authorization server itself and then we want to make sure the challenges match the one that we sent earlier when we initiated the authentication roundtrip if the challenge is match then a token is issued as a JSON object and sent to the application and it can begin consuming it pixie is more in line with the original flow that I talked about the authorization code flow and does not expose our token by passing them by a URL hash having said that all of these flows are pretty involved and the good news is that all of them are very well understood and implemented by SDKs so unless you work in the identity space you'll probably never actually have to implement these flows instead use an SDK that implements them for you just be aware of what flows are appropriate for what use cases if you're doing traditional server-side rendered applications authorization code flow if your author is it or actually that's what my next slide says so I'll just show it to you instead of saying it before I continue yeah so use the authorization code flow if you're building single page applications but your authorization server doesn't support pixie it's okay to use the implicit flow just be aware that there are some concerns that you need to be aware of if your authorization server does support pixie then definitely use the authorization code flow with pixie so that brings us to the second half of my talk which is how to implement a secure view Jaso plication and how do we take a generic authentication specification and weave it into a view application let's start with a bit of a checklist about what I'm going to be covering we'll add a global authentication service via dependency injection will restrict client-side routing based on authentication status will then handle authentication events like logout and login we'll look at conditional template formatting based on authentication status then we'll look at consuming ten ocation consuming the authenticated users open ID connect profile and then we'll wrap it up with how to send the access token along with any requests that you want to make to your API so authentication is a cross-cutting concern different portions of your application need to interact with it in different ways UJS offers two ways to handle cross-cutting concerns like that mix-ins are a flexible way of sharing functionality across view components you simply create an object that defines the shared methods that you want to be able to use and then declare them as a mixin as a part of your component definition but this isn't really what we're looking for when we're wanting to inject a global dependency instead plugins are a much better choice for this particular bit of functionality you're probably already familiar with using plugins if you've done any view development whatsoever both view router and view X are implemented as plugins to the view ecosystem here's a common example of adding Axios as a global HTTP request handler making it available for any component that might need it note that the comments show you which file each of these things live in we start at the top with my plugin definition where our import the Axios library and then I export a object that has an install method and then inside the install method I can poke around on the views prototype to add any objects I want to make them globally available to all other components so here I'm adding Axios as $8 HTTP variable then in the entry point for my view application main JSI just simply just import that plugin and then I tell you to use the plugin this is very similar syntax for using view X or router and then I when I'm implementing my component that needs to be able to make an HTTP call I can simply use the object off the this reference to get some data pretty simple so this makes plugging in our off service pretty clean in this example our main Jas imports the plug-in and tells view to use it passing along the configuration values that are needed the configuration values here are the domain of our authorization server the client ID I'm not passing a client secret because I'm passing it down to a browser which is an untrustworthy client but I can still pass the client ID which is basically used for identifying the application that's really all it's used for and then I'm passing an audience in as well I could also pass scopes here if I have I'm using global scopes and then the very last thing is a method allowing me to handle application state that will make more sense when I talk about the other end of that particular method where were consuming this so I'll save that for a minute okay so you may be thinking to yourself hey wait a minute where did this authorization service come from there's a whole bunch of math and fanciness involved that are I'm hiding under that create service call if you recall earlier I said you didn't need to be too concerned with generating or parsing cryptographic keys and that's because SDKs can handle that stuff for you and at a low level in in my sample I'm taking advantage of an SDK that auth0 released recently which was designed specifically for single page applications that was to use pixie the service is simply a thin wrapper over that SDK that makes it behave in a view like fashion so the underlying SDK is not specific to any one single page framework it's appropriate for any single page framework it will work in angular it will work in react workings felt if you go to the auth0 website and look for examples in those particular frameworks you'll see us using this sdk and how to consume them they're my examples are going to be all about view though so that brings us to another nifty feature of view and that's its reactivity model we're probably familiar with views reactivity model on a component that's defined kind of like this we start out defining a data element named foo with a template bound to it and its value bar when the mounted method executes it changes the value the foo value to Baz and views reactivity model will automatically update the templates value to match that value that reactivity is not limited to UI components though we can leverage it anywhere and the auth service implementation is simply another reactive view component that wraps the SDK exposing a set of reactive properties and methods that we can consume from any component this particular example handles the complex redirect logic described earlier then fetches the users profile and notifies anyone that cares that the user is authenticated this will come in handy later there's more to the service than what we see in this particular screenshot screenshot but you can check the the full functionality in the source code on your own in the github repository and with that we've injected a reactive authentication service packaged up nicely as a view plug-in so now that we have a reactive auth service we can start to leverage it to handle restricting access to our client-side routes in view router and view router is pretty is pretty easy to use and it's in common practice now out-of-the-box it offers several ways to make decisions about route navigation in this example we have two of the most common forms of route guards at the bottom of the screen we have a global route guard defined on the router itself that affects all routers or all routes defined in that given route and in the routes definition itself we have a per route guard that is applied directly only to that route definition the FUD the function signature for both is is exactly the same you're giving your given the route that we are navigating to the route that we're navigating from and a next method we can use to either allow the route navigation or to redirect the user back to some other portion of our application so with that in mind it's pretty trivial to implement a guard that takes our auth service into account the guard this guard will allow navigation if the user is authenticated or redirect them to the authentication server one thing to note here is that we passed some appstate along with the request that lets our application know where to send the user back to once they've successfully authenticated this is the flipside of the method that I was talking about earlier so basically with this implementation the user clicks the link whatever place they're trying to go to in your application they're directed to the authorization server to its indicate and then they come back to the exact place that we're trying to navigate to to begin with instead of being dumped in some random place in your app so back in our router we simply apply the guard to any routes we wish to require authentication in this example I'm applying it directly to a specific route but we could use it globally but we would need to make sure to exclude any public routes for consideration so if your application is predominantly private routes but you have like a landing page that needs to be public you need to select which type of route guard you want to use that's appropriate for your app and without we've restricted our client-side routes based on authentication with all that done we actually need to let the user log in and log out of our application and this is surprisingly simple with our login service exposed as a global service we literally just to find methods to call the relevant methods in our service here our logout method delegates login to login with redirect method that directs the browser to the identity provider for authentication there's an alternative method to do it in a pop-up if you don't want to have to redirect the entire browser the logout method simply makes a call to the identity provider to end the session so basically clear that cookie that I was talking about earlier and routes the user back to the root of our application with the methods exposed we simply call them by the click directive in our UI elements and with that we've handled with indication events and we've hit the halfway mark of our checklist there are times we'd like to show or hide elements in our applications based on the thin acacia thinik ated state of the user because the auth service is set up to be reactive and is exposed to all components conditional formatting is pretty trivial we can use the if directive to ask the service directly if the user is not authenticated show the login button if the user is authenticated show the logout button when the reactive values change the UI will update accordingly note we're also checking with the service to determine if it's in a loading state there's a brief period when the service calls back to the identity provider to get some details needed to validate tokens so we want to make sure that the service is ready before we start calling methods into it there's probably a better way to do that check I just haven't thought about it deeply enough to make it look nice so BAM that was the fastest one we've had yet when the users logged in we want to give them some indication that that's the case they logged in and this is also fairly simple thanks to the reactivity model here we use a computed property to return the user profile if it's available or the default values if they're not when the user becomes available it swapped in so we're reaching the finish line here good because I think I just saw my 5 minute mark if you recall when we configured the user service we also supplied an audience value which could have also specified a no any scops we wanted at that time as well the net effect of doing that is that we're issued an access token as I described before here is a component that loads its own data when it's mounted we simply ask the Earth's service for a token and make the request using an HTTP request service setting headers appropriately this book might look slightly differently if you're using a flux like library like view X but I think you get the idea one thing to point out here is that notice the service method is called get token silently this is a nice feature of the underlying SDK that I'm using it will check to see if the tokens we currently have in memory are expired and if they are it will silently request new ones from the authorization server which is very nice I don't have to worry about managing those tokens and juggling them myself so and with that we've completed our world one tour of securing a view jeaious app with open ID connect and ooofff and I am happy to thank you for your time and if you'd like to keep up with me you can find me in these various places once again you can find all the presentation materials at the bitly link at the bottom this is probably the slide you want to take a picture of also there is the source code for the demo app that I created that all of the sample code came out of so you can run that on your local machine I have various sets of stickers up here for you guys that are sticker orders like me I want to give a special thanks to my coworker Kim Maeda who graciously allowed me to borrow some of her theory explanations and diagrams for this presentation so thank you [Applause] okay so we have quite a few questions okay okay let's start first hole what would you say what would you say are the best resources to learn this stuff apart from talking to you sure I I don't want to sound like I'm Hawking my company but we are zero has really really good documentation and we want developers to understand Oh auth and open ID connect at a deep level so we have some great documentation and learning materials available on our website so I would start at auth0 comm slash docks and just start reading okay you've stated that the militia script running on your page could read the token from local storage yes any real-world examples and how that script could get there through an ad network so if you're serving up Google ads or something of that nature or you're relying on third-party NPM modules that you're not validating scripts can come in that way any thoughts in navigation guard sir versus middleware um not off the top of my head no I think guards are easier to understand in terms of you anyway I would be interested to know what use cases you have that would use middleware over a route guard is there some example of you app that demonstrates these flows and security best practices yes you'll find them at the bitly link how do you handle testing after implementing regards including show status hmm that's a good question the route guards themselves are a fairly pure function so you should be able to wrap the route guards themselves in unit tests without actually having to hit a authorization server so the guard that I showed for example will redirect to a URL you just mock out that particular piece of functionality and validate that it goes to the appropriate URL okay ezel zero still using JWT for authentication yes so most of the major identity as a service providers now have standardized on JWT s for all tokens so R 0 is one of them all of our tokens are JW T's but you need to keep in mind that you can't rely on Oh F tokens being JW TS it's not a part of the standard currently and some services don't use it one that comes to top of mind for me is twitch o-o auth tokens that you get from twitch are there's nothing you can do with them but send them back to twitch the principal engineer named Vittorio Bertucci at R 0 is a part of the working group that writes the OAuth specifications he's advocating an addendum to set the standard for JWT for all tokens but it hasn't been accepted yet okay and the last question for today it's possible for an app to have too old flows yes I'm sure it is but I would question why you would need to do it I want to give some deep thought into why you're doing that before actually trying to implement it there might be a better way of going about it ok so guys who posted this question feel free to come down and ask Bubbe after thank you all right thank you all and don't forget the stickers please come take [Music] [Music]
Info
Channel: Armada JS - JavaScript conference
Views: 1,786
Rating: 4.891892 out of 5
Keywords: armadajs, armada js, javascript, conference, js, vuewjs, oauth, konferencija, serbia, srbija, it
Id: r0BCki3U2AM
Channel Id: undefined
Length: 43min 41sec (2621 seconds)
Published: Thu Jan 09 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.