Coder Social home page Coder Social logo

gocloak's People

Contributors

akoserwal avatar alexsn avatar amaury95 avatar bastianccm avatar carmo-evan avatar dependabot[bot] avatar dlisin avatar effoeffi avatar fridafino avatar jpughcs avatar kisamoto avatar krisztianganyi avatar kveselkov avatar manju754 avatar moritz-muecke avatar mpawlowski avatar nerzal avatar nityanandagohain avatar ondrej-li avatar pp010 avatar svilgelm avatar timdrysdale avatar tjololo avatar toddkazakov avatar tomqwpl avatar tyrannosaurus-becks avatar vennekilde avatar viniciussousazup avatar yue-wen avatar zaletniy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gocloak's Issues

Add Method to initiate the reset password mechanism

Is your feature request related to a problem? Please describe.
The problem is easy. It's a missing feature.

Describe the solution you'd like
As described here we can trigger the "reset password" mechanism by calling the given URL.

Rather than specifying a new password manually a better security practice is to use the PUT /admin/realms/{realm}/users/{id}/execute-actions-email admin call with "UPDATE_PASSWORD" as the required action. This causes Keycloak to send an email to the user that gives a link for the user to set a new password.

Documentation:
https://www.keycloak.org/docs-api/4.8/rest-api/index.html#_users_resource

Variable Resources in PolicyRepresentation is always null

Issue description

When I call method GetPolicies am I getting all existing policies for my realm and client but when I try to access variable Resources in PolicyRepresentation I am getting always null and the resources exist because I have created them through admin ui.
Can be problem with mapping of the resources ?

Expecting behavior
Able to get resources through PolicyRepresentation.

Boolean values set to "false" are ignored

When I send request with bool field set to false, this field is not present in JSON.

	keycloakClientUuid := uuid.New().String()
	keycloakClient := gocloak.Client{
		ID: keycloakClientUuid,
		ClientID: "test",
		Name: "test",
		Enabled: false,
	}
	if err := keycloak.CreateClient(token.AccessToken, "compaas", keycloakClient); err != nil {
		return "", err
	}

JSON send:

{
  "clientId": "test",
  "id": "f522f163-2f7a-4857-a1da-5d4a21aa2b2c",
  "name": "test"
}

I believe that bool fields in models should be pointers.

Getting Realm roles for a user and a group

Is your feature request related to a problem? Please describe.
I need to receive all realm roles for a user and for a group.

Describe the solution you'd like
Would be great to have functions like GetRealmRolesByUserID, GetRealmRolesByGroupID

omitempty string attributes break when empty

Describe the bug
Setting an user's Email attribute to an empty string and updating the user does not actually remove the user's email address. The same goes for basically every string attribute.

To Reproduce
Steps to reproduce the behavior:

  1. Create user with an email address in Keycloak Admin Console.
  2. Query that user using gocloak (GetUserByID()).
  3. Set user.Email = ""
  4. UpdateUser()
  5. Observe in the Keycloak Admin Console that the user still has the email address.

Expected behavior
The user's email address is removed. This is expected behavior as this works if you delete the email address in the Keycloak Admin Console.

Additional context
Probably all string attributes (and possibly other attributes as well) should not have the json omitempty tag.
This was already addressed and removed for bool attributes.

Increase Test Coverage to >80%

In order to be more or less save for errors, when refactoring, we need a higher code coverage.
I'd say for v1 a Coverage of about 80% would be a good start

Realm creation fails on NPEs

Describe the bug
Any attempt to create a realm with an incomplete realm model fails.

To Reproduce
Steps to reproduce the behavior:

  1. Create a simple RealmRepresentation - fill in the name only
  2. Call ...CreateRealm(jwt.AccessToken, realm)
  3. Call fails with various NPEs on the keycloak side
    e.g.
09:05:37,241 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-1) Uncaught server error: java.lang.NullPointerException
        at org.keycloak.models.jpa.RealmAdapter.setBrowserFlow(RealmAdapter.java:1393)
...

Expected behavior
Realm created after the call

Additional context
I have a fix and will file a PR if that's OK.

UpdateClient doesn't work

Attempt to update client with UpdateClient method fails with error "405 Method Not Allowed".

Client will try execute PUT against wrong URL:

PUT /admin/realms/{realm}/clients

instead of

PUT /admin/realms/{realm}/clients/{id}

APIError as return type

Describe the bug
I see that from v5 is possible get more detail error as APIError but not sure how get from functions which are implemented in client because each function return standard error.

Expected behavior
Expected APIError as return type for every client function

client skip checking connection SSL

Is your feature request related to a problem? Please describe.

client := gocloak.NewClient(serverURL)
token, err := client.LoginClient(clientID, clientSecretKey, realmName)

error: 
Post https://<domain>auth/auth/realms/avlcloud/protocol/openid-connect/token: x509: certificate signed by unknown authority

Describe the solution you'd like
add last argument "false", to skip checking connection ssl

 token, err := client.LoginClient(clientID, clientSecretKey, realmName, false)

like this python code

from keycloak import KeycloakOpenID
keycloak_openid = KeycloakOpenID(server_url=SERVER_URL,
                    client_id=CLIENT_ID,
                    realm_name=REALM_NAME,
                    client_secret_key=CLIENT_SECRET_KEY,
                    verify=False)

how to implement authorization functions?

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Add support for client certificates

Is your feature request related to a problem? Please describe.
In order to securely connect to keycloak with client certificates I'd like gocloak to support it.

Describe the solution you'd like
Client certificate connection is described here: https://www.keycloak.org/docs/3.3/server_admin/topics/authentication/x509.html
The underlaying resty library can be configured to use client certificates: https://godoc.org/gopkg.in/resty.v1#Client.SetCertificates

Describe alternatives you've considered
Use another library to connect to keycloak (or default to go's HTTP client). This would take considerably more time and effort.

Support realm removal

Gocloak supports realm creation and realm listing but missing a realm deletion functionality.

Can we get it?

In essence it should just do a DELETE on the realm.

See official documentation for more.

Update readme to setup keycloak in docker and change parameter in tests

Is your feature request related to a problem? Please describe.
Currently you have to add a super.secret.go file containing constants, which let you run the tests.

Describe the solution you'd like
It would be super nice, if we add a section to the readme.md which provides a copy&paste solution to start a new keycloak instance.

The tests should use parameters to use this keycloak instance

How to skip (X509) certificate validation in gocloak?

I am trying to validate my token from keycloak using goloak and tyring the below code for that..

token:=""
client:= gocloak.NewClient("https://example.com")
_, err := client.RetrospectToken(token,"client-id" ,"client-secret", "realm")
log.Print(err.Error())
the I am getting below error,

Post https://example.com/auth/realms/realm/protocol/openid-connect/token/introspect: x509: certificate signed by unknown authority

is there any way to skip the certificate validation in gocloak.

Regenerate Client Secrets

Is your feature request related to a problem? Please describe.

It is not possible to trigger the regenerate secret endpoint for a client.

Describe the solution you'd like

A simple method to regenerate a client secret

Describe alternatives you've considered

Using the UpdateClient method or calling the API directly

Additional context

Unable to create Client

When I'm creating client without Id field set, empty Id is send to Keycloak. In result Id is not auto-generated and Client can't be accessed.

	keycloakClient := gocloak.Client{
		ClientID: "test",
		Name: "test",
		Enabled: false,
	}
	return keycloak.CreateClient(token.AccessToken, "test", keycloakClient)

In database:

MariaDB [db4keycloak]> select ID, CLIENT_ID, NAME from CLIENT where NAME LIKE 'test';
+----+-----------+------+
| ID | CLIENT_ID | NAME |
+----+-----------+------+
|    | test      | test |
+----+-----------+------+

Manage federated identities of an user

Is your feature request related to a problem? Please describe.
No api to manage federated identity of an user (maybe I'm missing something)

Describe the solution you'd like
Functions for the following calls

  • GET /{realm}/users/{id}/federated-identity
  • POST /{realm}/users/{id}/federated-identity/{provider}
  • DELETE /{realm}/users/{id}/federated-identity/{provider}

Describe alternatives you've considered
I implement it myself. Unfortunately, there are also some supporting functions in gocloak private, which would make this a bit easier

Adding and deleting client-level roles to the user role mapping

Hi,

I'm using gocloak to automate user management in keycloak, and I need to manage client roles for my users. I tried to use the AddRealmRoleToUser and DeleteRealmRoleFromUser functions with my client roles in the input parameters, but I get a 404 error (that's pretty predictable). Therefore I didn't find any methods in the gocloak package that handled these two methods.

API endpoints are described here: https://www.keycloak.org/docs-api/2.5/rest-api/index.html#_delete_client_level_roles_from_user_role_mapping_2

Actually, what I need is AddClientRoleToUser and DeleteClientRoleFromUser functions pointing to these methods' endpoints.

I'm thinking of adding theses functions on my own because I don't have much time to make it happen, maybe this is already possible and I didn't find how to do it ? So Before I start coding this on my side, I ask it here :)

Thanks !

Christophe.

Add method to set new password

Is your feature request related to a problem? Please describe.
Missing feature, which needs to be implemented

Describe the solution you'd like
Make a call to PUT /auth/admin/realms/master/users/{id}/reset-password
Example Body: { "type": "password", "temporary": false, "value": "my-new-password" }

Info comes from here

It would be nice if CreateGroup returned the created group's id

I'd like the signature of CreateGroup to change from

CreateGroup(accessToken string, realm string, group Group) error

to

CreateGroup(accessToken string, realm string, group Group) (string, error)

This would match the signature of CreateUser which already returns a user id. I'd be happy to write a pull request for this but I wanted to run it by you first because I'm not sure if it's okay to change the interface of an existing method.

Thanks!

A little help needed

I'm trying to add gocloak module to mine as a dependency but something strange happens. Can you please explain to me what I'm doing wrong and why this is the result?

  1. add the import in my go file like this

import "github.com/Nerzal/gocloak"

  1. add this to my go.mod file

require github.com/Nerzal/gocloak v2.0.0

  1. I build with go build and my go.mod file got overridden like this

require github.com/Nerzal/gocloak v0.0.0-20190525151100-dfd1e50572f8

Get User Credentials API

Is your feature request related to a problem? Please describe.
Current there is no API to get user credentials

Describe the solution you'd like
API to get user credentials.

Additional context
Add any other context or screenshots about the feature request here.
Screenshot 2020-03-21 at 1 58 05 AM

curl 'https://SERVER/auth/admin/realms/{REALM}/users/{USERID}/credentials' 

RESPONSE:

[{"id":"12296c78-b9ad-4ef4-a272-e801f8ae44a6","type":"password","createdDate":1584731908202,"credentialData":"{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}"}]

Bumping versions

As we discussed in Slack, the repo is already mature enough to have the versions for each commit/sets of commits merged into master.

My suggestion is using the Semantic Versioning 2.0.0: https://semver.org/#semantic-versioning-200:

Given a version number MAJOR.MINOR.PATCH, increment the:

MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.

To make it easier, I want to create a bump_version script, which will scan all tags, find the latest and increase the PATCH by one or use , then it should create a tag and push it.

Feature RememberMe handle by REST API

Feature RememberMe handle by REST API
I try to find way how can be handle feature RememberMe by REST API. Actually I cannot find API which will provide this kind feature. The remember me can be managed just by login page of the Keycloak if I am not wrong.

Solution
Would be great if the login method which is responsible for to login user also provide boolean parameter for rememberMe. But also should be exist some API from the Keycloak side.

clientID is not that id by keycloak

gocloak version v5
keycloak verison 9.0.0

Every clientID argument is a uuid , not keycloak Client ID

My kaycloak Manage page show me Client ID is app,and that app url is

<hostname>/auth/admin/master/console/#/realms/demo/clients/8bb0f130-a60e-4575-a6fb-56d3bc2f85e2
8bb0f130-a60e-4575-a6fb-56d3bc2f85e2

is a clientID for argument ,
If I input app to clientID , It's 404

404 Not Found: Client not found

So, I consider it's not friendly

Add go dep support

Describe the bug
I tried to use this library in my project, where I use go dep.

Therefore, I added the following entry to my Gopkg.toml file:

[[constraint]]
  name = "github.com/Nerzal/gocloak"
  version = "v3.2.0"

However, when I run dep ensure, I receive the following error:

Solving failure: No versions of github.com/Nerzal/gocloak met constraints:
	v2.1.0: Could not introduce github.com/Nerzal/[email protected], as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	v3.2.0: "github.com/Nerzal/gocloak" imports "github.com/Nerzal/gocloak/v3/pkg/jwx", which contains malformed code: no package exists at "github.com/Nerzal/gocloak/v3/pkg/jwx"
	v3.1.0: Could not introduce github.com/Nerzal/[email protected], as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	v3.0.0: Could not introduce github.com/Nerzal/[email protected], as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	v2.0.1: Could not introduce github.com/Nerzal/[email protected], as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	v2.0.0: Could not introduce github.com/Nerzal/[email protected], as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	v1.0.0: Could not introduce github.com/Nerzal/[email protected], as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	master: Could not introduce github.com/Nerzal/gocloak@master, as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	Nerzal-patch-1: Could not introduce github.com/Nerzal/gocloak@Nerzal-patch-1, as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	change_clientscoperepresentation: Could not introduce github.com/Nerzal/gocloak@change_clientscoperepresentation, as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	fix_executeActionsEmail: Could not introduce github.com/Nerzal/gocloak@fix_executeActionsEmail, as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	v1.0: Could not introduce github.com/Nerzal/[email protected], as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.
	v2: Could not introduce github.com/Nerzal/gocloak@v2, as it is not allowed by constraint ^3.2.0 from project livestockfinder-server.

To Reproduce
Add entry from above to Gopkg.toml file and run dep ensure.

Expected behavior
Whould be great if I could import this project with go dep for dependency management.

Desktop (please complete the following information):

  • OS: Windows 10
  • dep version:
dep:
 version     : v0.5.0
 build date  : 2018-07-26
 git hash    : 224a564
 go version  : go1.10.3
 go compiler : gc
 platform    : windows/amd64
 features    : ImportDuringSolve=false

Keycloak token introspection always fails with {“active”:false}

Describe the bug
Testing the introspection to know if the token is in active state, it always gives false.
If there is another way to prove this, please describe it.

To Reproduce
Steps to reproduce the behavior:

	client := gocloak.NewClient(url)
	token, err := client.Login("account", client_secret, realm,username,password)
	if err != nil {
		panic("Login failed:"+ err.Error())
	}

	rptResult, err := client.RetrospectToken(token.AccessToken, client_id, client_secret, realm)
	if err != nil {
		panic("Inspection failed:"+ err.Error())
	}

	if !rptResult.Active {
		panic("Token is not active")
	}

Expected behavior
It should return token information and its active status

{"exp":1574658355,"iat":1574656555,"aud":aud,"active":true,"jti":jti,"typ":typ}

Additional context
Keycloak Version < 4.8 (gopkg.in/nerzal/gocloak.v1)

Investigating I found that the solution is to add the following data in the message body: client_id, client_secret, username.

// RetrospectToken calls the openid-connect introspect endpoint
func (client *gocloak) RetrospectToken(accessToken string, clientID, clientSecret string, realm string,username string) (*RetrospecTokenResult, error) {
	var result RetrospecTokenResult
	resp, err := getRequestWithBasicAuth(clientID, clientSecret).
		SetFormData(map[string]string{
			"client_id":     clientID,
			"client_secret": clientSecret,
			"username": username,
			"token":           accessToken,
		}).
		SetResult(&result).
		Post(client.basePath + authRealms + realm + tokenEndpoint + "/introspect")
	err = checkForError(resp, err)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

Use APIError

Is your feature request related to a problem? Please describe.
It would be nice to get the status code returned from Keycloak.

Describe the solution you'd like
Return APIErrors from gocloak calls. This could be tricky for errors resulting from things other than Keycloak API calls.

Describe alternatives you've considered
Can't think of any though I'm totally open to any existing solutions I'm unaware of.

Additional context
I have my own HTTP service in front of gocloak and right now it's hard to determine what errors and response codes I should return. For example I might get an error back like this "400 Bad Request: Password policy not met. See logs for details".

I'd like to be able to set my response code to 400 and set an appropriate error of "Password policy not met." The "See logs for details" part doesn't really make sense but I'm not sure there is anything that can be done to solve that.

Client.BaseURL JSON mapping has incorrect case

Describe the bug
When updating a Keycloak ClientRepresentation which contains a baseUrl field via UpdateClient, Keycloak responds with a 400 Bad Request: "Unrecognized field "baseURL" (class org.keycloak.representations.idm.ClientRepresentation), not marked as ignorable"

This is because the JSON mapping of Client.BaseURL has the incorrect case baseURL, rather than the expected baseUrl for the Keycloak API.

We are using Keycloak 7.0.

To Reproduce
Steps to reproduce the behavior:

  1. In Keycloak, create a Client, and set a Base URL.
  2. Execute the following code:
	client := gocloak.NewClient(conf.Server)
	token, err := client.Login(conf.AdminClientID, conf.AdminClientSecret, conf.AdminRealm, conf.AdminUser, conf.AdminPassword)
	if err != nil {
		err = errors.Wrap(err, "Something wrong with the credentials or url")
		return err
	}
	params := gocloak.GetClientsParams{
		ClientID:    clientID,
		ViewableOnly: false,
	}
        //Find the client you've created, with the given clientId
	appClients, err := client.GetClients(token.AccessToken, realm, params)

	if err != nil {
		err = errors.Wrapf(err, "Couldn't get client with id %v", clientID)
		return err
	}
	appClient := appClients[0]
	body, err := json.Marshal(*appClient)
	klog.V(2).Infof("Client Body:\n%v", string(body))
	err = client.UpdateClient(token.AccessToken, realm, *appClient)
	if err != nil {
		err = errors.Wrapf(err, "Failure updating client")
			return err
	}
  1. Get 400 error

Expected behavior
UpdateClient should PUT a well-formed ClientRepresentation JSON object and receive a 200 response.

fatal error: concurrent map writes (client.GetCerts())

Hi,

Lately, I experienced some crashes with gocloak involving the client.GetCerts (client.go) function.
I took a look to this function to understand why and I think I have a solid explaination.

This function tests if certs are present in client.certsLock. If they're present, it returns the map, end of the game. If they're not, the function fetch them with client.getNewCerts(realm) and writes them to client.certsCache. After that a goroutine waits a given delay and deletes the old certs.

When a customer comes back after that, certs are missing and the function manages to get new ones... Good game, but…

When a customer comes back at the exact moment the timer goes on certs deletion, 2 map read/writes occurs at the same moment and crash the whole process.

I'll send a PR in minutes to fix that using a Mutex to protect client.certsCache read and writes.

Have a good day :)

Unknown client when try to get policies

Describe the bug
I try to get policies for my realm and client which I have created but always when I call GetPolicies by client I am getting 404 Not Found: Could not find client. The wierd think is that another API endpoints I am able to call.
Any hints where could be the problem becuase the client with realm should be OK.

Expected behavior
Get array of all policies.

Additional context
I am using gocloak v5 and the newest version of Keycloak which is 9.0.0.

runtime error: invalid memory address or nil pointer dereference

Describe the bug
Not checking nil

To Reproduce
Issue is here https://github.com/Nerzal/gocloak/blob/master/client.go#L245

The code:

usedKey := findUsedKey(decodedHeader.Kid, certResult.Keys)
token, err := jwx.DecodeAccessTokenCustomClaims(accessToken, usedKey.E, usedKey.N, claims)

usedKey is not checked for nil.

It should be:

usedKey := findUsedKey(decodedHeader.Kid, certResult.Keys)
if usedKey == nil {
  return nil, errors.New("cannot find a key to decode the token")
}

return  jwx.DecodeAccessTokenCustomClaims(accessToken, usedKey.E, usedKey.N, claims)

Expected behavior
Not to crash with a panic

URL for GetGroup incorrect

Attempt to load group by id with GetGroup method fails. Client will try to use URL:

/admin/realms/{realm}/group/{id}

instead of

/admin/realms/{realm}/groups/{id}

Add Go Module support

Is your feature request related to a problem? Please describe.
We have to add Go Module support.

Describe the solution you'd like
We have to add Go Module support.

Additional context
As some people started using gocloak we have to be aware, that possible breaking changes are not that nice anymore. As i want to keep on refactoring & extending the lib, we need to take care that these changes don't break existing projects.

Adding go module support is a step towards this direction, as users of this lib can chose which version they want to depent on.

Edit: Oh i forgot, there are old go.mod and go.sum files. I guess these need to be updated.

Not able to LoginClient

My keyclaok instance is set up in a corporate network and I am successfully able to generate token in POSTMAN but I am facing issue while handling it in my golang API.

client := gocloak.NewClient("https://keycloakt.iservice..corporateserver/auth/realms/i-service/protocol/openid-connect/auth")
clientID := "test-data"
clientSecret := "11550ca3-2437-451f-b66e-80bdf9dd8a5a"
realm := "I-service"
token, err := client.LoginClient(clientID, clientSecret, realm)
if err != nil {
	panic("Login failed:" + err.Error())
}

On run, its give panic saying - Login failed:404 not found.

'To configure client, I tried the access token URL as well as the issuer URL for keycloak client but in every case it gives Login failed:404 not found.

Is your library needs any proxy details to connect to keycloak server ?

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.