Giter Site home page Giter Site logo

Comments (6)

travisghansen avatar travisghansen commented on May 22, 2024 4

@polarathene wow, great questions! I'll do my best to explain and see if we can get you sorted out. A pretty big maxtrix of types of services exist which make the overall situation complicated and at times difficult to understand.

At it's core, eas is not trying to be an identity provider. I felt like ldap and services providing oidc etc were doing a pretty good job of that. That's probably the biggest difference with Authelia. It likely most closely resembles Pomerium in that context, however, a couple key differences exist even on that front:

  1. pomerium (from what I can tell) is strictly bound to oidc (you could of course use something like keycloak to expose oidc backed by ldap etc)
  2. pomerium configuration is more static, requiring different installations for housing vastly different configurations (ie: different oidc providers completely)

That's not a knock against either project, both are great, just focused on different things. I'm fairly certain the pipeline idea in eas is fairly unique to this project but could exist out there elsewhere.

Now, regarding actual services, I would say they typically fall into categories based on the following:

  1. Do they understand authentication natively or not? (ie: many simple services simply have no notion of authentication and expect authentication to happen outside the app if at all)
  2. Do they have any real notion of users/accounts?
  3. Others?

If something natively understands authentication then I'd recommend using that (assuming it works with your backing store for unified accounts/credentials). After looking at BookStack it appears they understand oidc quite well, you may even be able to configure it to work with Keycloak using one of the existing providers (ie: 'trick' it into doing oidc with keycloak with the okta provider or the like).

If something does not natively understand/implement authentication then this project is great candidate...especially if they don't have any real notion of users/accounts.

Then you have a relatively rare breed, which is something like grafana which does understand users/accounts and also has natively authentication (particularly the built-in DB), but can handle auth externally. In the vein of SSO this is also a prime candidate for eas (I and several others use this project for grafana).

You also have several other use-cases where a project doesn't necessarily understand users/accounts (meaning, they have no meaning to the app) but optionally allow you to turn on some crude (usually basic auth with a static single user account/password) authentication mechanism. This is true of projects like sabnzbd, radarr, sonarr, lidarr, and about a million others. If you want true SSO you could put each of those behind eas.

Lastly, like the grafana situation, if you're actually developing an app and want to use oidc, but don't want to implement the whole workflow, then using a project like this makes sense (ie: you expect a valid jwt to reach your service in whatever fashion the client gets it).

In my case, I use ldap for users and configured keycloak backed by the same ldap store. This gives me unified set of credentials to use. Services that natively understand oidc/ldap I simply use their ocnfigurations. Services that don't I generally put 'behind' eas. The eas configuration is setup with a pipeline that understands oidc and basic auth so I can handle end-user (oidc) clients and machine (ldap via basic auth) clients on the same endpoint with the same config.

Let me know if there's anything else I can share to help out!

from external-auth-server.

travisghansen avatar travisghansen commented on May 22, 2024 2

Yeah, lots of good stuff here and great questions. I'm pretty pragmatic so ultimately use whatever best fits your needs for sure. Also note I don't consider myself an 'expert' in the arena either...this whole project was more of a "I seem to always be fighting these solutions, I guess I'll make my own that does what I need" situation. In that vein I was aware of several of the alternatives you're digging into. A handful of criteria led me to my own:

  1. some tools were specific to certain proxies
  2. I'm not super excited to add another proxy (ie: oauth2_proxy, gatekeep, etc) for a couple reasons
    1.1 operationally it can be a headache to deploy those 'in front' of whatever you're actually deploying, for example (not sure if you use kubernetes) but deploying with a helm chart or the like it's highly unlikely the chart supports injecting random proxies along with the service
    1.2 requires you deploy new instances for each service and/or config variation (this project embeds config in the URL so a single deployment can service essentially unlimited number of services/providers/configurations)
  3. some solutions don't let you pass down portions of a jwt (or even the whole jwt) to backing services
  4. some don't actually refresh tokens, gather userinfo, or generally reup the auth data (ie: you authenticate, a cookie is created (sometime long living) and nothing is checked until the cookie expires and the whole process starts over)
  5. I wanted more than oidc to better handle machine to machine scenarios. This can be mitigated to some degree (ie: manually issue a long-lasting token and auth against that) but I generally didn't love the options.
  6. re-iterate the dynamic config mentioned above but outside the context of proxies...I wanted the service to be essentially stateless. This proved challenging but outside a caching mechanism and optionally using server-side tokens I've achieved it. Even server-side tokens can be essentially stateless when served up via a ENV variable or simple json config file.
  7. I wanted ability to have complete control over the authorization process as well. At least in the context of allowing certain endpoints/routes/verbs to be allowed without authentication.
  8. Separation of duties. Many options probably support this but it's good to note/consider. I wanted the ability to keep the holders of the secrets and issuers of the config separate from those running services which simply use the authentication server. For example deploying with a 'proxy' solution is unlikely to operate in this fashion. In the case of this project, the eas server itself can be managed by a security/identity team, and they simply create encrypted config_tokens and hand that off to operators wanting to use/add authentication. Because the config_token is encrypted, operators deploying services that use eas do not necessary need to know oidc details, or ldap server connection strings, etc.

Regarding a UI, it is conceivable to create one and I've considered it longer term. However given the attempt to be as stateless as possible, it UI doesn't make a lot of sense. It basically could/would serve 2 purposes as I see it:

  1. Wizard for creating config_tokens to ease that configuration process. There is quite a lot of power involved with this project making this particular idea a pretty daunting task. However, for basic use-cases it's probably pretty easy to knock out.
  2. If using server-side tokens (for example backed by a SQL DB) it could act as a management interface to those (including the wizard mentioned above). ie: "I want to issue a new config, step me through the wizard and store it in the DB..now let me see all the tokens I've issued and give me an option to revoke them etc"..by tokens here, I mean config_tokens, not authentication tokens for individual users.

Back to your addressing your specific questions/comments from above.

There are a couple ways of viewing SSO I suppose. There's literal SSO where if I've already signed into the IDP (identity provider) I don't have to a second time (even though I may be redirected there and immediately be redirected back to the desired service without the user even noticing). More broadly (and generally more important to me) is having a unified set of credentials..even if I have to login multiple times, I'm using the same account.

You certainly could achieve SSO with 'social' providers but then you have to question whether you want your users to have an account directly with you or not. This question is entirely subjective and there's no blanket 'right' answer. Even using Keycloak you can actual federate your users via social IDP. For example you can deploy Keycload and set it up to authenticated via google OIDC (super confusing, I know). If I were wanting to run my own community I'd probably run with housing my own accounts in an LDAP server and using keycloak (or alternatives) to add oidc support but all backed by the same LDAP user/group store.

That would place EAS in the same category as other projects that protect services behind an SSO proxy/gateway right? With EAS being one of the few that supports a wider range of auth protocols?

If I use Keycloak as my auth provider, they also have Keycloak Gatekeeper, which seems to be capable of achieving the same functionality(along with a UI for login if you're not deferring to an external auth provider like Google/Okta). Would EAS be serving the same purpose as Gatekeeper, or can it compliment it?

Yes it does. Yes, same purpose as gatekeeper. When used with something like keycloak you would be redirected to the exact same login screen keycloak provides as gatekeeper would do (see above for why I personally don't love extra proxies in this context).

Is there a proper / common term for this type of auth? Seems unfortunate that it's not as common. For BookStack I tried to look into the PHP Laravel libraries for auth, and they seem to be Laravel Socialite and Laravel Passport, but it's not clear to me if either can provide the same auth functionality Grafana is able to offer.

I don't know of a term for this. There could be one. Laravel using socialite and password are likely implementing much of what this kind of project does, but doing so natively. I would be highly surprised if you cannot make BookStack (ie: socialite/passport) point at a generic oidc provider. I mean, everything is there and clearly already understood for several of the bigger providers implementing the spec.

Basic auth as in the browser dialog pop-up using htpasswd? With EAS are you moving that to be handled by EAS instead of per service?(and thus able to use anything else like OAuth/OIDC providers or JWT?

Yeah, you could use eas to 'front' those with oauth/oidc...but this is a place where eas gets interesting. Basic auth doesn't have to be htpasswd, in fact I serve up basic auth using ldap connection. In particular, these services are highly likely to have 2 kinds of users, end-users, and machine/api users. Since my keycloak is backed by the same LDAP users I can authenticate the same service using a unified set of users for both basic auth (back by LDAP) and oidc (backed by keycloak..back by the same LDAP). So if I want to configure something using the API I simply plugin the same username/password as I would type into the keycloak interface if sent there. I specifically handle this situation using the pcb functionality of eas and look for the Authorization header. If it's present and has a value starting with Basic then I target the LDAP integration, if not, it's assumed it's not an api-style user and keycloak/oidc/sso stuff kicks in.

That sounds like a really good use-case! Sort of like Laravel Socialite/Passport, but language agnostic? I assume it's like using Keycloak Gatekeeper, and optionally Keycloak or something else for user management if needed, but perhaps EAS is simpler to integrate with?

It's for projects that may not have access to something like socialite/passport..or simply doesn't want to integrate the workflow at all. You would use something like keycloak for IDP and the backing service simply expects a jwt as some header (usually the Authorization header with a strategy of Bearer).

Ah ok, I take it you were aware of Gatekeeper before building EAS, what was the motivations for such vs using an existing solution like Gatekeeper? Were there missing features, or did you need something lighter/simpler, what is the selling point here for choosing EAS?(nothing against it btw, it seems like a great option!)

See reasons above. Again, I'm pretty pragmatic so my feelings aren't hurt if another project fits the needs better. Pomerium + Keycloak seem like a pretty good option for what I'm gathering you're doing. While eas doesn't have a fancy UI, it does have some advanced features that you may not find in Pomerium. In which case, eas + keycloak backed by LDAP would be highly recommended.

That'd work for personal use for me or a small team. I may have to go with that if it's not feasible to pull them all under one SSO umbrella implicitly for users that register to the community.

There may be a disconnect here. You'll likely have a mix of apps that do natively understand oidc, and some that don't. When using eas + 'those apps' both configured to use the same keycloak instance would certainly provide an SSO experience across the board. Again, consider the meaning of 'SSO' as well.

Say you configured BookStack to natively communicate with a keycloak instance, and then fronted some generic service with eas pointed to the same keycloak instance. Let's also assume that user1 tried to access BookStack, was redirected to login at keycloak, did so, and was returned to BookStack all authenticated etc. Now consider they attempt to access a service fronted by eas (or generally any of the options you're looking at which support oidc). Presumably eas has not created a session for them yet, so they are redirected to keycloak to login, upon arrival at the keycloak login screen keycloak detects they are already logged in, so they are redirected back to the original service (ie: eas fronted service) without ever even seeing the login screen. Upon arrival back at the service eas checks to make sure all is in order and let's them through. It's a complicated series of redirects but most of them the user is probably completely unaware of as the browser does it so fast they don't even notice. That's SSO at work for both an app the 'natively' understands oidc and one that doesn't.

Ultimately, you're going to run into services (lots of management UIs for example expect authentication to happen outside) that don't to authentication and don't really care about users (meaning, needing to know the difference between userA and userB...they either are authenticated or they are not). Maybe these aren't even things you want your broader community to access but internal admins. eas makes it so you can leverage your existing login/SSO for those sites as well. Giving you the ability for example to say, you can only access this service if you can login (SSO) and if you belong to group X (presumably LDAP groups sync to keycloak). Or even target specific users, so even if someone is 'logged in' it doesn't necessarily mean you want them to access management interface X or Y.

Hopefully some of this babbling is helping :)

from external-auth-server.

polarathene avatar polarathene commented on May 22, 2024

I think the answer is to ensure that all services support the same SSO provider, and that your provider allows for Dynamic Client Registration(Keycloak, Auth0).

That should allow for automating each user joining the community to be linked to each service without requiring them to link each account themselves? Then each service can use the SSO support provided to login once and be logged in to the rest of the services they're permitted access to.

Not quite sure how EAS fits into that approach, if at all.

from external-auth-server.

polarathene avatar polarathene commented on May 22, 2024

After looking at BookStack it appears they understand oidc quite well, you may even be able to configure it to work with Keycloak using one of the existing providers (ie: 'trick' it into doing oidc with keycloak with the okta provider or the like).

My goal is more of many services like this being provided for a community, where a user should ideally only register to the community in one place, and ideally have all services they're able to use already connected to the SSO account(probably not doable for third-party services like BookStack with external providers like Google, but for self-hosted SSO like Keycloak perhaps there is a way). A user shouldn't have to come across the forum or wiki services and register/connect to their main community account, even if it's a one off setup per user.

I'll need to understand this all much better to know how possible that is to implement in practice, perhaps it's only suitable for a few niche third party services like Grafana and the rest as first party.

If something does not natively understand/implement authentication then this project is great candidate...especially if they don't have any real notion of users/accounts.

That would place EAS in the same category as other projects that protect services behind an SSO proxy/gateway right? With EAS being one of the few that supports a wider range of auth protocols?

If I use Keycloak as my auth provider, they also have Keycloak Gatekeeper, which seems to be capable of achieving the same functionality(along with a UI for login if you're not deferring to an external auth provider like Google/Okta). Would EAS be serving the same purpose as Gatekeeper, or can it compliment it?

but can handle auth externally. In the vein of SSO this is also a prime candidate for eas (I and several others use this project for grafana).

Is there a proper / common term for this type of auth? Seems unfortunate that it's not as common. For BookStack I tried to look into the PHP Laravel libraries for auth, and they seem to be Laravel Socialite and Laravel Passport, but it's not clear to me if either can provide the same auth functionality Grafana is able to offer.

This is true of projects like sabnzbd, radarr, sonarr, lidarr, and about a million others. If you want true SSO you could put each of those behind eas.

Basic auth as in the browser dialog pop-up using htpasswd? With EAS are you moving that to be handled by EAS instead of per service?(and thus able to use anything else like OAuth/OIDC providers or JWT?

Lastly, like the grafana situation, if you're actually developing an app and want to use oidc, but don't want to implement the whole workflow, then using a project like this makes sense (ie: you expect a valid jwt to reach your service in whatever fashion the client gets it).

That sounds like a really good use-case! Sort of like Laravel Socialite/Passport, but language agnostic? I assume it's like using Keycloak Gatekeeper, and optionally Keycloak or something else for user management if needed, but perhaps EAS is simpler to integrate with?

In my case, I use ldap for users and configured keycloak backed by the same ldap store. This gives me unified set of credentials to use.

Ah ok, I take it you were aware of Gatekeeper before building EAS, what was the motivations for such vs using an existing solution like Gatekeeper? Were there missing features, or did you need something lighter/simpler, what is the selling point here for choosing EAS?(nothing against it btw, it seems like a great option!)

Services that natively understand oidc/ldap I simply use their ocnfigurations.

That'd work for personal use for me or a small team. I may have to go with that if it's not feasible to pull them all under one SSO umbrella implicitly for users that register to the community.

from external-auth-server.

polarathene avatar polarathene commented on May 22, 2024

I would be highly surprised if you cannot make BookStack (ie: socialite/passport) point at a generic oidc provider. I mean, everything is there and clearly already understood for several of the bigger providers implementing the spec.

Perhaps that's something I don't have a good understanding of. Generic provider to me just means generic support for other providers not officially listed in their docs, even if they had one that was specifically for Keycloak or whatever provider I use, a user would need to access services like BookStack upon first visit(after registration) and connect/link that service to the original account/provider they registered with?

Rephrased into steps:

  • User visits community forum and decides to join the community to post in the forum.
  • They click login or the forum action redirects them to do so, that redirects to auth.mydomain.com.
  • User is new, so they must register an account(be that username/password or anything Keycloak offers for example, perhaps allowing for external auth providers like Google or Facebook to link/initialize their community account).
  • Verification step(eg email) if needed, otherwise user community account is now valid and redirects back to forum
  • User later wants to contribute to the wiki, login redirects to auth.mydomain.com to authenticate?

Confusion for me here is that the wiki service has no knowledge of the forum service, and for authentication only knows it supports XYZ providers to create an account with and link that provider to the account. I'm not sure if the redirect to auth.mydomain.com works in this setup, I assume it'd work the same with Google/Facebook as the provider redirecting to an external URL to ask the user for consent to connect the service to their provider, in which case I've missed a step and each service will have their own login/register pages with available providers to connect, with only keycloak going to my auth.mydomain.com for purposes of linking/consent, not recognizing the user already has a community account and using the existing login session without consent.

At least, when I think of how it works with Google/Facebook/Github when I have used them for services I've joined, they rightfully require consent. If I self-host a provider like Keycloak, all my services on my domain should be able to implicitly have consent, and just go straight to auth.mydomain.com to acquire login state or have the user login(which could be username/password for self-host registration, but I'm also of the understanding that external auth providers like Google/Facebook could be linked for this "entrypoint/gateway", while all my hosted services use the hosted keycloak instance as the provider:

Services -- Keycloak provider (OIDC/SAML/OAuth2/JWT)(each service implicitly links, no consent, auth handled here) -- keycloak username/password or external SSO auth provider(community wide account, only used to login into the community, external auth provider or username/password aren't tied to the individual services)

As if I signed up for Googles suite of services, where some were third-party services rather than first-party/inhouse, and I signed up with Facebook as the SSO provider(logged into Facebook, allows access to any service on the community that my user is authorized to access, among any other websites the facebook account is providing SSO for unrelated to my community).

BAD: Wiki service could be signed up and linked to Google. Forum service could be signed up and linked to Facebook. An additional auth layer is of no use here for a public community.

GOOD: Centralized auth, implicitly linked services to a user account. Adding another service or replacing an existing one, migrate data(if replacing), configure app to implicitly link users to central auth layer(IDP). Existing user visits new service and is already logged in, no need to manually create account by linking to Keycloak.

Sorry for repeating myself, just making sure the scenario is clear.

The confusion with BookStack as an example, was even with a Keycloak provider, doesn't it need to be linked by the user first? I would need something like Grafana's feature that implicitly creates the account with auth headers, or a programmatic API feature compared to a services typical login/account page?

There is no need for UI like Pomerium / Authelia, EAS fits in fine between the services and auth domain that my self-hosted keycloak provider prompts user for sign-up or login if not already logged in. Although I'm not sure if EAS needs to sit inbetween the service and auth provider in this situation.


Again, consider the meaning of 'SSO' as well.

For me that might be keycloak at auth.mydomain.com, you login there or get redirected to it from a service, and then you're logged in to all available services(authorized by policy like roles/groups). That login could be via username and password, or if using external SSO provider, you are signed in to all community services from being signed in to that SSO providers login.

In the sense of an external SSO provider, I only want that link with keycloak, not a user linking individual services(or keycloak itself afterwards).

Not sure if I've understood the meaning of SSO correctly, I think that's correct.

There may be a disconnect here. You'll likely have a mix of apps that do natively understand oidc, and some that don't. When using eas + 'those apps' both configured to use the same keycloak instance would certainly provide an SSO experience across the board.

I understand that some services may not use OIDC, or have any concept of users/accounts and just need their route protected from the outside world to only authorized users, non-issue at present, the above one just focused on OIDC is complicated enough for me to grasp for now(implicit linking) :)

Pomerium + Keycloak seem like a pretty good option for what I'm gathering you're doing. While eas doesn't have a fancy UI, it does have some advanced features that you may not find in Pomerium. In which case, eas + keycloak backed by LDAP would be highly recommended.

Currently, I think I'll just be focusing on Keycloak(and perhaps Gatekeeper), due to documentation/features and resources online about it. Once I've got some experience with that setup, Pomerium or EAS will probably be more obvious in value going forward, especially for an eventual adoption of k8s(just a single 16GB quad-core VPS with docker-compose for now). AFAIK, Keycloak is already backed with built-in LDAP(although it can use an external one), so I'll again just stick with that for now.

you could use eas to 'front' those with oauth/oidc...but this is a place where eas gets interesting. Basic auth doesn't have to be htpasswd, in fact I serve up basic auth using ldap connection.

BookStack has LDAP suppport, but the docs state that a user logins with the username/password from LDAP, it didn't seem to imply that any existing LDAP session(if there is such thing) is carried over not requiring a user to login to the service. So I figured I'd go with Keycloak as an OIDC provider, which manages LDAP underneath and provides the same data through that?(eg claims).

If basic auth allows for me to provide the login/redirect flow with auth.mydomain.com and pass back info for generic auth to the service, that sounds good? Or is LDAP in this case just providing the username/password that htpasswd would contain, still requiring a prompt from the user to input?

Yes it does. Yes, same purpose as gatekeeper. When used with something like keycloak you would be redirected to the exact same login screen keycloak provides as gatekeeper would do (see above for why I personally don't love extra proxies in this context).

That's helpful, thanks. Especially regarding k8s scenario, I'm not particularly fond of layering proxies for this myself.

You certainly could achieve SSO with 'social' providers but then you have to question whether you want your users to have an account directly with you or not.

Currently the bulk of the community if users on a heavily modified/extended forum software. They all register through Steam(OpenID 2, not OIDC) as the only option.

I would like them to be able to create an account with Keycloak, which handles logging them into all the provided services, but this account afaik can be setup/linked to a social provider as a means of logging in?(I believe keycloak refers to it as identity brokering). The keycloak account though would manage the user data for services to access/share.

Regarding a UI, it is conceivable to create one and I've considered it longer term. However given the attempt to be as stateless as possible, it UI doesn't make a lot of sense.

I don't think EAS needs a UI, if I understand it's purpose. UI is provided by the auth/identity provider(s) when not already logged in?(for browser users at least)

For management UI of config, not an issue, I'm fine with configs without UI, I'm sure a companion project could provide such if there was demand for it.


Say you configured BookStack to natively communicate with a keycloak instance, and then fronted some generic service with eas pointed to the same keycloak instance.

Yes I get this flow, and have seen a few diagrams representing it. That's all fine once the user has their account(or account per service?) linked to the SSO provider. If they haven't used Service X before, what happens? They get redirected to a screen asking how they want to setup an account?(username/password or connect to a supported SSO provider)

If BookStack were this Service X, presumably it needs some way to recognize this user already logged into auth.mydomain.com... which thinking about it, it must do(cookie/token in HTTP headers?). I've been thinking of it in the sense that it provides it's own login page with support for multiple SSO providers, so those would each have their own auth redirects.

Doesn't help that I'm jumping straight into trying to achieve this not having implemented simpler single project auth support myself before(I'm a developer but never implemented such myself, user accounts were already handled). Still, BookStack would need a way to recognize the user on first visit, even if that auth info is there, it may not have a user account that it can look up internally to associate with? Perhaps that's where the LDAP support comes in(if BookStack supports using that with OIDC).

I think I need to dig into the docs for keycloak and set that up with BookStack and some other services(I have BookStack already running in production, but it manages it's own accounts for a few users trialing it).

from external-auth-server.

travisghansen avatar travisghansen commented on May 22, 2024

Yeah I think you'll be well served by setting up an instance and messing around a bit. Generally what happens (if the service natively understands oidc) is after successfully auth the user is redirected back to the service but this time has a token. The service actually (generally) creates a user in they're own DB/whatever and just links it up to the oidc user.

What I mean by generic provider is a generic oidc provider. Since oidc is a spec it's a bit silly for them to have specific configuration options for google/azure/etc when they all do the same thing. Technically all you need is an endpoint (sometimes a few) to be configured and move on. Since keycloak implements oidc it should 'just work'.

LDAP only happens to be one of the stores keycloak supports for users. I simply recommend it because inevitably you'll end up with something needing to be authenticated that can't/doesn't use odic, in which LDAP is pretty well the de-facto. Think of VPNs, git, etc, etc (stuff not necessarily even http/websites). If you're using LDAP for your users generally and then configure keycloak to use that as your store, at least you'll have unified list of accounts and passwords for your users.

from external-auth-server.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.