sphereon-opensource / siop-oid4vp Goto Github PK
View Code? Open in Web Editor NEWSelf Issued OpenID Provider v2 (SIOP) with optional OpenID for Verifiable Presentations (OpenID4VP)
License: Apache License 2.0
Self Issued OpenID Provider v2 (SIOP) with optional OpenID for Verifiable Presentations (OpenID4VP)
License: Apache License 2.0
When importing the library it prints to the console.
It should not print to the console when you import the library.
Importing the library like so
import { OP, PresentationExchange } from "@sphereon/did-auth-siop";
output
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV1/properties/_const" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV1/properties/_enum/items" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV1/properties/exclusiveMinimum" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV1/properties/exclusiveMaximum" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV1/properties/minimum" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV1/properties/maximum" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV2/properties/_const" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV2/properties/_enum/items" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV2/properties/exclusiveMinimum" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV2/properties/exclusiveMaximum" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV2/properties/minimum" (strictTypes)
strict mode: use allowUnionTypes to allow union type keyword at "#/definitions/FilterV2/properties/maximum" (strictTypes)
During presentation exchange I noticed that the same validations or decoding of jwt token in underlying methods happens multiple times.
Problem in PresentationExchange.validatePresentationsAgainstDefinition(). Here you have filterOutCorrectPresentation() method that invoke pex.evaluatePresentation() and do filtering to get only correct presentation definitions. After that in validatePresentationsAgainstDefinition() you have the same pex.evaluatePresentation() to do validation. But actually you made this validation previously, so no point to do this one more time. And at the end of method you have PresentationExchange.validatePresentationAgainstDefinition() where you one more time create PEX and call evaluatePresentation() for validation.
So maybe you can revise this method and optimize it so that you don't do the same checks multiple times. Because it slows down the presentation exchange process.
I was working to implement JWK thumbprint as a possible subject_syntax_type for Self Issued ID Token. Especially when used in combination with vp_token and SD-JWT VCs that are bound to JWKs it's beneficial to not have to use a did (although you can convert the jwk to e.g. a did:key or did:jwk, it's nicer to not have to do this).
However after doing some refactorings, I ran into that issue that this library heavily depends on did-jwt, which as the name suggests focuses on JWTs signed by dids.
What would be the best way forward around this? Not leveraging did-jwt for JWTs not signed by dids is possible, but it would require a lot of code then that could also be used for did-jwt.
I'm not sure if did-jwt could support other mechanisms than dids, but looking at the package name, I'd assume it's out of scope.
Another possbility would be to make the suppiled signature more complex to configure and allow to plug in your own jwt implementation. e.g. in AFJ we have our own JWS / JWT implementation, so we could manually sign the whole JWT payload if we get the input payload and headers. Then this library by default would only support did signing, and if you want JWK signing you need to pass in something yourself.
Related to #55
There are a lot of DID methods which depend on other signing algorithms. I feel that at least ed25519 and sr25519 should be added to support polkadot based DID solutions.
Is this something that might have a chance to land in here? I could also have a look how to add it, if I get positive feedback!
Great project btw. really appreciated.
Hi,
I think I found an issue in /functions/DIDResolution.ts
:
Please note that uniResolvers
is an array, so ...uniResolvers
will send N args to the Resolver
constructor (where N is the number of elements of the array). Causing that only the first element of the array is configured as resolver.
Proposed fix, use a json object instead of array:
let uniResolvers = {};
for (const didMethod of opts.didMethods) {
const uniResolver = getUniResolver(getMethodFromDid(didMethod), { resolveUrl: opts.resolveUrl });
uniResolvers = { ...uniResolvers, ...uniResolver };
}
return new Resolver(uniResolvers);
It appears that the verifier must use _enum
and _const
for the generation of the presentation definition
in the description of the fields
, e.g.
constraints: {
fields: [
{
path: ['$.credentialSubject.role'],
filter: {
type: 'string',
_const: 'admin',
},
},
]
}
or
constraints: {
fields: [
{
path: ['$.vc.credentialSubject.degree.name', '$.credentialSubject.degree.name'],
filter: {
type: 'string',
_enum: ['Bachelor of Science and Arts'],
},
},
],
},
Why is this necessary, couldn't the keywords enum
and const
be used directly (even though we understand that these are reserved keywords in Javascript).
Getting an error unless I install sha.js
manually
Hi all, I was trying your library following your tutorial but I'm stuck at "OP Auth Request verification" point.
I'm using your "@sphereon/did-auth-siop": "^0.3.0"
library version.
I was able to create an AuthorizationRequest
correctly, obtain the encodedURI
and return it.
This is an example:
openid-vc://?request=eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2poYXJTOXpWRVJmdnQ0Q29Lb1FmUERyd1Q4aGZRRVRQYnhxWThvcVl1SjY0IiwidHlwIjoiSldUIn0.eyJpYXQiOjE2ODQzMTkwMjAsImV4cCI6MTY4NDMxOTE0MCwicmVzcG9uc2VfdHlwZSI6ImlkX3Rva2VuIiwic2NvcGUiOiJvcGVuaWQiLCJjbGllbnRfaWQiOnsiaWRfdG9rZW5fc2lnbmluZ19hbGdfdmFsdWVzX3N1cHBvcnRlZCI6WyJFZERTQSJdLCJyZXF1ZXN0X29iamVjdF9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIkVkRFNBIiwiRVMyNTYiXSwicmVzcG9uc2VfdHlwZXNfc3VwcG9ydGVkIjpbImlkX3Rva2VuIl0sInNjb3Blc19zdXBwb3J0ZWQiOlsib3BlbmlkIGRpZF9hdXRobiIsIm9wZW5pZCJdLCJzdWJqZWN0X3R5cGVzX3N1cHBvcnRlZCI6WyJwYWlyd2lzZSJdLCJzdWJqZWN0X3N5bnRheF90eXBlc19zdXBwb3J0ZWQiOlsiZGlkOmV0aHI6IiwiZGlkOmtleToiLCJkaWQiLCJkaWQ6ZXRociIsImRpZDprZXkiXSwidnBfZm9ybWF0cyI6eyJqd3RfdmMiOnsiYWxnIjpbIkVkRFNBIl19fX0sInJlZGlyZWN0X3VyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODc4Ny9hcGkvb3BlbmlkL0F1dGhSZXF1ZXN0Q2FsbGJhY2siLCJyZXNwb25zZV9tb2RlIjoicG9zdCIsIm5vbmNlIjoiMTExMSIsInN0YXRlIjoiQ3JlYXRlZCIsInJlZ2lzdHJhdGlvbiI6eyJpZF90b2tlbl9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIkVkRFNBIl0sInJlcXVlc3Rfb2JqZWN0X3NpZ25pbmdfYWxnX3ZhbHVlc19zdXBwb3J0ZWQiOlsiRWREU0EiLCJFUzI1NiJdLCJyZXNwb25zZV90eXBlc19zdXBwb3J0ZWQiOlsiaWRfdG9rZW4iXSwic2NvcGVzX3N1cHBvcnRlZCI6WyJvcGVuaWQgZGlkX2F1dGhuIiwib3BlbmlkIl0sInN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjpbInBhaXJ3aXNlIl0sInN1YmplY3Rfc3ludGF4X3R5cGVzX3N1cHBvcnRlZCI6WyJkaWQ6ZXRocjoiLCJkaWQ6a2V5OiIsImRpZCIsImRpZDpldGhyIiwiZGlkOmtleSJdLCJ2cF9mb3JtYXRzIjp7Imp3dF92YyI6eyJhbGciOlsiRWREU0EiXX19fSwiY2xhaW1zIjp7InZwX3Rva2VuIjp7InByZXNlbnRhdGlvbl9kZWZpbml0aW9uIjp7ImlkIjoiMTIzNC0xMjM0LTEyMzQtMTIzNCIsImlucHV0X2Rlc2NyaXB0b3JzIjpbeyJpZCI6IkV4YW1wbGVJbnB1dERlc2NyaXB0b3IiLCJzY2hlbWEiOlt7InVyaSI6Imh0dHBzOi8vZGlkLml0c291cndlYi5vcmc6MzAwMC9zbWFydGNyZWRlbnRpYWwvT250YXJpby1IZWFsdGgtSW5zdXJhbmNlLVBsYW4ifV19XX19fSwibmJmIjoxNjg0MzE5MDIwLCJqdGkiOiJhMjdiOGUzMi04NmRiLTQyY2UtYTg1Yi1kY2ExMWFhZDdhOTQiLCJpc3MiOiJkaWQ6a2V5Ono2TWtqaGFyUzl6VkVSZnZ0NENvS29RZlBEcndUOGhmUUVUUGJ4cVk4b3FZdUo2NCIsInN1YiI6ImRpZDprZXk6ejZNa2poYXJTOXpWRVJmdnQ0Q29Lb1FmUERyd1Q4aGZRRVRQYnhxWThvcVl1SjY0In0.dL7uJfXK-AO_-TYEPxNvK-pcC4UU_Zyqv32p0xUah-VlqOIfrETzZ3h5LqaUJ6dHyNoqgbQgNdB1HKpDKRgEDg
Then when I try to verify it using the method OP.verifyAuthorizationRequest()
passing the URI above it gives me this error:
TypeError: authorizationRequestPayload.client_id.startsWith is not a function
at /node_modules/@sphereon/did-auth-siop/src/authorization-request/Payload.ts:107:45
at AuthorizationRequest.<anonymous> (/node_modules/@sphereon/did-auth-siop/src/authorization-request/AuthorizationRequest.ts:156:39)
It's a function from Typescript String library, so I don't know what the problem could be. Any ideas?
reqURI.nonce
doesn't exist nor does reqURI.state
Old example:
const reqURI = await rp.createAuthenticationRequest({
nonce: "qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg",
state: "b32f0087fc9816eb813fd11f"
});
console.log(`nonce: ${reqURI.nonce}, state: ${reqURI.state}`);
// nonce: qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg, state: b32f0087fc9816eb813fd11f
console.log(reqURI.encodedUri)
// openid://?response_type=id_token&scope=openid&client_id=did.......&jwt=ey..........
Updated example:
const reqURI = await rp.createAuthenticationRequest({
nonce: "qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg",
state: "b32f0087fc9816eb813fd11f"
});
console.log(
`nonce: ${reqURI.requestOpts.nonce}, state: ${reqURI.requestOpts.state}`
);
// nonce: qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg, state: b32f0087fc9816eb813fd11f
console.log(reqURI.encodedUri)
// openid://?response_type=id_token&scope=openid&client_id=did.......&jwt=ey..........
Currently, it is not supported to send multiple VPs in the authorization repsonse, if the request only contained a single presentation definition. The number of VPs must match the number of PDs.
However, we're currently creating multiple VPs for a single PD, so that we can authenticate multiple credential subjects (as a JWT VP can only have one signature).
I can't read from the spec that this is invalid, however it would probably require some changes in PEX as well, as it's currently not really possible to have a single Presentation Submission for multiple VPs as well (had to do some hacks to combine multiple submissions into one larger submission)
Hi, I found that my sdjwt need to append a "~" in order to work, if not I will encountered Error: compact JWT must include two periods (.).
but now if I solve that issue, i encounter another one jwt is not valid for usage with sd-jwt-vc. Error: Claim key 'typ' was found, but values did not match, should i add vc+sd-jwt at my JWT header?
btw, this is my vp_token
eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa3M0QXFXamRHRHhicEdkVGhUWnhiU014a3d1OGE3VGs1WFRYaHY5ZENVOFBlI3o2TWtzNEFxV2pkR0R4YnBHZFRoVFp4YlNNeGt3dThhN1RrNVhUWGh2OWRDVThQZSIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJodHRwczovL2NsaWVudC5leGFtcGxlLm9yZy9wb3N0IiwiZXhwIjoxNzM4MTQwOTkxLCJpYXQiOjE3MDY1MTg1MzEsImlzcyI6ImRpZDprZXk6ejZNa3M0QXFXamRHRHhicEdkVGhUWnhiU014a3d1OGE3VGs1WFRYaHY5ZENVOFBlIiwianRpIjoidXJuOnV1aWQ6MzJjMjA1ZGUtOTIwMC00NzI1LTgyMmYtZTE0YzdkZGU4OGFmIiwibmJmIjoxNzA2NTE4NTMxLCJub25jZSI6InFWakpWX2dseFVFIiwic3ViIjoiZGlkOmtleTp6Nk1rczRBcVdqZEdEeGJwR2RUaFRaeGJTTXhrd3U4YTdUazVYVFhodjlkQ1U4UGUiLCJ2cCI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJob2xkZXIiOiJkaWQ6a2V5Ono2TWtzNEFxV2pkR0R4YnBHZFRoVFp4YlNNeGt3dThhN1RrNVhUWGh2OWRDVThQZSIsImlkIjoidXJuOnV1aWQ6MzJjMjA1ZGUtOTIwMC00NzI1LTgyMmYtZTE0YzdkZGU4OGFmIiwidHlwZSI6WyJWZXJpZmlhYmxlUHJlc2VudGF0aW9uIl0sInZlcmlmaWFibGVDcmVkZW50aWFsIjpbImV5SmhiR2NpT2lKRlpFUlRRU0o5LmV5SmZjMlJmWVd4bklqb2ljMmhoTFRJMU5pSXNJbVY0Y0NJNk1TNDNNelE0TXprMk1qUmxLekE1TENKcFlYUWlPakV1TnpBMk1EQXhNelF4WlNzd09Td2lhWE56SWpvaVpHbGtPbXRsZVRwNk5rMXJkVlU0U20xRVdrbzVabnBTV2tSdU1WaEdUamx0WlRkVWFXUnlkalZ0TTNsTVN6bFpaMHRpUjBkTllrMGlMQ0pxZEdraU9pSTFNRE14TVdWaU15MDJNV0l3TFRSalpqa3RZbVZoTlMxak1EY3daVFEwWWpZM1kyTWlMQ0p1WW1ZaU9qRXVOekEyTURBeE16UXhaU3N3T1N3aWMzVmlJam9pWkdsa09tdGxlVHA2TmsxcmN6UkJjVmRxWkVkRWVHSndSMlJVYUZSYWVHSlRUWGhyZDNVNFlUZFVhelZZVkZob2RqbGtRMVU0VUdVaUxDSjJZeUk2ZXlKQVkyOXVkR1Y0ZENJNld5Sm9kSFJ3Y3pvdkwzZDNkeTUzTXk1dmNtY3ZNakF4T0M5amNtVmtaVzUwYVdGc2N5OTJNU0pkTENKZmMyUmZZV3huSWpvaWMyaGhMVEkxTmlJc0ltTnVaaUk2ZXlKcWQyc2lPbnNpWTNKMklqb2lSV1F5TlRVeE9TSXNJbXQwZVNJNklrOUxVQ0lzSW5naU9pSjFlakoxZEdOUGVraGhURUpFU1dFNFR6VnVTRE52YzNNNU1sbGFiWE5MVVcxWGJEQkZiRjl1Y1VGVkluMTlMQ0pqY21Wa1pXNTBhV0ZzVTNWaWFtVmpkQ0k2ZXlKZmMyUWlPbHNpT1ZvemJHMWlZbVZLY2kxcVZGUmZTa1pJUjNadGFqZFJTME5yZVRWRFJGZE5TbGROUVZwbGVtUnBieUlzSWpkak9HNVVWMFZWYjNoRlRFcEtka2Q1YjNWRlQxcGtiR1Z1Y1dFdE5GbGFNazEwVUUxNGJYWkhNMEVpTENKMFkyWlZVRk41V0ZKRFZYTXpRbVpzT1dkalIydEpPVTFLVms0NU5rOTNNRzlqY2t0V09UWmFSVTlqSWwwc0ltUmxaM0psWlNJNmV5SmZjMlFpT2xzaWFYWkZabUZyWldSUlFtNVNTMlpqYWt4TWRuTm1PWFJDV21jMmJFRXllbVJ1TVU1c1pWQTBWbHBDTUNJc0lsbFBabVJRZGtoNVoySjFhMjlGWjFrMFIyNXRjRzFtTlY5dGVrUjRTVFI1YVdWRFIybE5lbWxQZDFraUxDSkxNMkZIUmxsRVNuQm9YMDVJVDIxa1prTndVbXh2YWpWemJuRnhiRWRtVFdNdE9UVjRRVGR6V1ZaWklsMTlmU3dpYVdRaU9pSm9kSFJ3T2k4dlpYaGhiWEJzWlM1bFpIVXZZM0psWkdWdWRHbGhiSE12TVRnM01pSXNJbWx6YzNWaGJtTmxSR0YwWlNJNklqSXdNalF0TURFdE1qTlVNVGM2TVRVNk5ERXVNREF3TURBd01EQXdLekE0T2pBd0lpd2lhWE56ZFdWeUlqb2laR2xrT210bGVUcDZOazFyZFZVNFNtMUVXa281Wm5wU1drUnVNVmhHVGpsdFpUZFVhV1J5ZGpWdE0zbE1TemxaWjB0aVIwZE5ZazBpTENKMGVYQmxJanBiSWxabGNtbG1hV0ZpYkdWRGNtVmtaVzUwYVdGc0lpd2lWVzVwZG1WeWMybDBlVVJsWjNKbFpTSmRmWDAuNUp5OFRQTlZPOGxHUm9RVWVia0psTFJIellJSmpfM0E1Zmg1TkMtdDJOaDlwX01hQktBUUxFdUZ0UFZvTG50eGFsYmoxNlNJZDdlQkdDUnlaSDJvRGd-V3lKNU4xWm5PRGxRY1hKNWRtVjJTMmxFY1VWNVRVZFJJaXdpYm1GdFpTSXNJa3BoZVdSbGJpQkViMlVpWFEiXX19.A6kOGerOOO2MNa_DX3iA0VvfKkuxxAYFLn5OBFyQXJxm6X_1JlS7S3DZ5bRDfl3zzJ_tEi1DpmZMZJXT_fU8Bw
Hi,
Do you have plans to support OpenID4VP ID1
/JWT VC Presentation Profile
spec?
I know that there are a lot of specifications and different versions about that, but it seems like this specific one is used by Microsoft Entra.
Thank you
I think we've sort of discussed this before, but just wanted to open an issue to continue the discussion.
We're currently integrating this library into Aries Framework JavaScript (AFJ), and one of the things that was really nice about the OID4VCI and PEX libraries is that they're really lightweight and don't pull in any crypto or did related libraries.
In AFJ we have a did resolver, JWT signer/verifier, and support for several crypto suites. That way we don't have to pull in all the dependencies for this. (I think especially did-jwt
pulls in a lot of crypto related dependencies).
Hi,
I'm wondering if the rp.verifyAuthenticationResponseJwt
is taking into account the integrity of the VCs included into the VP.
For example, to detect a possible scenario where a (malicious) holder has changed some attributes of the VC (like credentialSubject
) before submit the VP to the relying party (verifier).
Thank you
Is the RP class designed to be able to have only one instance for all the users (SIOPs) trying to authenticate to the relying party or I have to make one instance for each user that tries to auth/authz? Thanks
About 30-50% of the time calls to verifyAuthenticationRequest()
fail. Network tab shows that requests are pending/failing for DID resolution against https://dev.uniresolver.io/1.0/identifiers/did:ethr:.....
.
How can this resolver be replaced with something else?
Hello there!
I just found that the PresentationExchange.selectVerifiableCredentialsForSubmission
method is throwing error when pejs.selectFrom
includes at least 1 error as part of the result: https://github.com/Sphereon-Opensource/did-auth-siop/blob/2954cd53967e763fe4ca28918f208732d2779403/src/main/PresentationExchange.ts#L100-L102
I'm wondering what's the reason to do that, without checking by selectResults.areRequiredCredentialsPresent === 'info'
before: https://github.com/Sphereon-Opensource/pex/blob/beb25e231d22858cfcccc075c1d1454dac36568b/lib/evaluation/core/evaluationResults.ts#L6-L15
Please correct me if I'm wrong but the selectResults.errors
array will always contains elements unless that all of the VCs specified in the PresentationExchange constructor (allVerifiableCredentials
property) meet the provided presentation definition.
Thank you
Hi, I have tried multiple vp_token from our company that following the current latest specification, but seems that is not able to verified by your library, that are many errors thrown. For example , 'Inconsistent issuance dates between JWT claim (${nbfDateAsStr}) and VC value (${issuanceDate})', and many other problem, May I have your one sample jwt_vp to investigate our ?
Hi,
May I know there is a support for create authorization request on direct_post ode with the response_uri and verify it? because I cannot make it works
Is it currently possible to create an Authorization request based on the (SI)OP configuration?
There's some static ones defined, as well as a SIOP could host an openid-configuration at a well-known endpoint.
Is it possible to create an authorization request based on the configuraiotn ,or would you have to parse it yourself and create a valid RP based on this?
E.g. if you want to use the static siopv2://
configuration, only id_token
is supported as response_type
and also the URL should start with siopv2://
.
It seems that the current behavior for the PEX implementation is to wrap jwt-vcs and execute the filter on the wrapped version.
It is not clear to me from the spec if this should be the case.
For instance, this example seems to target the jwt-decoded version of a jwt-vc:
Anyways, I am just looking for your thoughts on this.
Thank you very much
If presentation verification fails (verified=false) in presentationVerificationCallback then application raise event AuthorizationEvents.ON_AUTH_RESPONSE_VERIFIED_SUCCESS
RpBuilder.wothPresentationVerification(presentationVerification) seems like is not being awaiting
I want to respond to a verifier requesting credentials in jwt_vc
format.
An example of a response can be found here:
https://identity.foundation/jwt-vc-presentation-profile/#id-token-example
and should contain some descriptor_map
with the following example content:
"descriptor_map": [
{
"id": "InteropExampleVC",
"format": "jwt_vp",
"path": "$",
"path_nested": {
"id": "InteropExampleVC",
"format": "jwt_vc",
"path": "$.verifiableCredential[0]"
}
}
]
where the format
is jwt_vc
.
However, I haven't found a way to actually create such an id_token
. When checking the repo I have found the following code with a hard-coded format: 'ldp_vc'
, see
How can I achieve the creation of a properly formed id_token
for jwt_vc
credentials?
Hi there,
Can you please confirm what version of the OpenID Connect for Verifiable Presentations
draft are you implementing in the release/v2.0.0 branch?
I thought you were following v1.0-10 (22 April 2022), but there is a significant difference in the authentication response:
vp_token
parameter along with id_token
and state
.release/v2.0.0
branch, just an id_token is submitted to the RP. https://github.com/Sphereon-Opensource/did-auth-siop/blob/dcc36321e2012f27ab049316480e9a1e8745b3e2/src/main/functions/HttpUtils.ts#L27-L35Do you have plans to change this part or am I missing something?
Thank you!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.