faker
faker copied to clipboard
add `jwt` to `internet` module
Clear and concise description of the problem
As a developer, I use faker to "seed" my documentation examples. I was currently writing a section about the usage of the JWT token in my system. For visualization purposes, I wanted to provide an example JWT so developers can see what to expect. Sadly faker doesn't provide such a feature (at least not in the internet module where I would expect it).
Suggested solution
Add a basic jwt function to the internet module that returns a string that is a JWT. So it should be "decryptable" but has a random signature.
I don't think it's necessary to input a payload object since that would get too close to a real implementation (?).
Alternative
Currently, I use a hardcoded JWT (with incorrect signature and expired) for my documentation.
Additional context
No response
[!NOTE]
This issue has been marked with "good first issue". If you'd like to get started contributing to this project, this is the issue for you! The issue can be solved by following the acceptance criteria layed out in the team decision comment
What would be the benefit of a generated invalid token over a static expired one?
Just so I understand you correctly. You suggest doing the following:
@MyDocumentationDecorator({
example: myJwtLib.generate(realPayload, secret, { expiresIn: dateInThePast }),
})
This is not possible for me because the part where I write the documentation doesn't depend on the implementation of the JWT generation (or any business logic tbh). So I'm not able to access myJwtLib because it's abstracted in a way that only the service that is responsible for JWT generation knows the exact implementation.
And to go a step further I'm not able to use that service in the documentation due to it (the documentation) being a decorator based and the services have to be injected by the framework for dependency resolution.
One more thing: My current solution works perfectly fine (with a static/hardcoded JWT string). I just like to have example values change every time you reload to documentation, but its not required.
I'd be interested in Faker having this too.
Please upvote the issue if you are interested in having this in Faker. That way we can track user interest.
Please upvote the issue if you are interested in having this in Faker. That way we can track user interest.
Silly question but how do I upvote?
With "upvote" we mean the +1 (👍) reaction in issues and PRs.
But I saw that you already found it 👍
More information on reactions can be found on "Add Reactions to Pull Requests, Issues, and Comments"
Thank you for your feature proposal.
We marked it as "waiting for user interest" for now to gather some feedback from our community:
- If you would like to see this feature be implemented, please react to the description with an up-vote (:+1:).
- If you have a suggestion or want to point out some special cases that need to be considered, please leave a comment, so we are aware about them.
We would also like to hear about other community members' use cases for the feature to give us a better understanding of their potential implicit or explicit requirements.
We will start the implementation based on:
- the number of votes (:+1:) and comments
- the relevance for the ecosystem
- availability of alternatives and workarounds
- and the complexity of the requested feature
We do this because:
- There are plenty of languages/countries out there and we would like to ensure that every method can cover all or almost all of them.
- Every feature we add to faker has "costs" associated to it:
- initial costs: design, implementation, reviews, documentation
- running costs: awareness of the feature itself, more complex module structure, increased bundle size, more work during refactors
An example call could look like:
const jwt: string = faker.internet.jwt({
algorithm: faker.internet.jwtAlgorithm(),
refDate: faker.date.past(),
});
But what should be returned?
Should header contain { alg, typ }?
Should payload contain { sub, name, exp, iat }?
Or more specifically:
What are your requirements/expectations?
- Which headers?
- Which values?
- Valid signature?
Proposal for minimalistic API implementation
The following text uses "Requirement Levels" based on RFC 2119
What are your requirements/expectations?
As stated in my original feature request:
Add a basic jwt function to the internet module that returns a string that is a JWT. So it should be "decryptable" but has a random signature.
I don't think it's necessary to input a payload object since that would get too close to a real implementation (?).
We can asset multiple things here:
- the JWT value MUST fulfil the semantical contract based on RFC7519
- the JWT signature MAY be valid
- the generation function MAY take a payload argument
- the generation function MUST provide a default payload argument (to fulfill the contract)
- the generation function MAY take a header argument
- the generation function MUST take a header argument (to fulfill the contract)
Additionally, I suggest that the initial method SHOULD be as minimalistic as possible.
The following sections are suggestions that should summarize the higher level implementation details for faker.internet.jwt.
Headers
- The header MUST be a base64 encoded object
- The header object MUST include the properties "typ" and "alg"
- The
typproperty SHOULD always be'JWT' - The
algproperty SHOULD be chosen randomly from a list of valid algorithm values as defined in RFC7518
Payload
- The payload MUST be a base64 encoded object
- The payload object MUST include the properties "exp" and "iat"
- The property "exp" MAY be a number given by
faker.date.anytime().valueOf() - The property "iat" MAY be a number given by
faker.date.anytime().valueOf()
- The property "exp" MAY be a number given by
- The payload MAY include any other Registered Claim Names
- The property "iss" MAY be a random company name given by
faker.company.name() - The property "sub" MAY be a UUID given by
faker.string.uuid() - The property "aud" MAY be a UUID given by
faker.string.uuid() - The property "nbf" MAY be a datetim string given by
faker.date.anytime() - The property "jti" MAY be a UUID given by
faker.string.uuid()
- The property "iss" MAY be a random company name given by
- The payload MUST NOT include any other property not stated so far
Signature
- The signature MUST NOT fulfill the contract of RFC7518
- The signature MAY be an alphanumeric string
- The signature MAY have a random length
- The signature MUST be at least 20 character
Example implementation
jwt(): string {
const header = {
alg: randomJwtHeaderAlgorythm(), // abstracted here
typ: 'JWT',
};
const payload = {
iat: this.faker.date.anytime().valueOf(),
exp: this.faker.date.anytime().valueOf(),
};
const encodedHeader = Buffer.from(JSON.stringify(header)).toString('base64url');
const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64url');
const signature = faker.random.alphaNumeric(64);
return `${encodedHeader}.${encodedPayload}.${signature}`;
};
Feel free to give feedback on the proposal.
- The header object MUST include the properties "typ" and "alg"
These headers are also optional according to the spec. I didn't find any specifics regarding alg at all. Maybe lets consider alg as required.
- The payload object MUST include the properties "exp" and "iat"
These claim names are also optional according to the spec.
Additionally, I suggest that the initial method SHOULD be as minimalistic as possible.
If it should be as minimalisistic as possible, it should omit all optional fields.
Which basically results in {"alg": "HS256"}.{}.ZRrHA1JJJW8opsbCGfG_HACGpVUMN_a9IV7pAx_Zmeo
eyJhbGciOiJIUzI1NiJ9.e30.ZRrHA1JJJW8opsbCGfG_HACGpVUMN_a9IV7pAx_Zmeo
What is your intention doing with such a value? Since it doesn't contain any values (and is invalid) what can you do with it? If you cannot do anything with it, why not hardcode the first two parts? Or just use 3 random base64 strings?
It would be a different matter if you could provide the/additional header and payload entries. Then you could actually create JWT tokens according to your needs (except their signature). But then again why would your application ever process a JWT token, that isn't valid?
Providing a valid signature isn't possible without specific libraries, not available in all environments (e.g. node:crypto)
- The header object MUST include the properties "typ" and "alg"
These headers are also optional according to the spec. I didn't find any specifics regarding alg at all. Maybe lets consider alg as required.
- The payload object MUST include the properties "exp" and "iat"
These claim names are also optional according to the spec
My comment was not a summary of RFC7519 but a "Proposal for minimalistic API implementation" (as stated in the first heading) - a suggested specification for the implementation. If this intent was not clear enough, I apologize for that.
Additionally, I suggest that the initial method SHOULD be as minimalistic as possible.
If it should be as minimalisistic as possible, it should omit all optional fields. Which basically results in
{"alg": "HS256"}.{}.ZRrHA1JJJW8opsbCGfG_HACGpVUMN_a9IV7pAx_Zmeo
eyJhbGciOiJIUzI1NiJ9.e30.ZRrHA1JJJW8opsbCGfG_HACGpVUMN_a9IV7pAx_Zmeo
While this would be true when strictly following the RFC, I'd argue that real-world use cases nearly always include the "typ" property in the header as well as the properties "exp" and "iat" in the payload. That's the reason why I suggested including them.
What is your intention doing with such a value? Since it doesn't contain any values (and is invalid) what can you do with it? If you cannot do anything with it, why not hardcode the first two parts? Or just use 3 random base64 strings?
It would be a different matter if you could provide the/additional header and payload entries. Then you could actually create JWT tokens according to your needs (except their signature). But then again why would your application ever process a JWT token, that isn't valid?
As stated in my original comment as well: The workaround with a static value works for me. My use case was to generate dynamic example values in the documentation I was working on back then. Non-tech people (testers) had to use an API interface (think swagger) and had to extract the JWT they got from a response. The documentation showed them the value of the format that they could expect. My use case might not be the most sophisticated but seeing that this issue collected over 20 upvotes during the last year I'd say that the necessity from the community is given.
Providing a valid signature isn't possible without specific libraries, not available in all environments (e.g. node:crypto)
Agreed, this is why I made the statements in the suggestion, covering the necessity to not include valid signatures.
Team Decision
- We accept the
faker.internet.jwtfeature. - We will have header and payload options that replace the default values
- The defaults will be defined according to the sample/spec outlined here: https://github.com/faker-js/faker/issues/1282#issuecomment-2073340189
- Additionally:
- exp should be derived from iat (
faker.date.soon({refDate: iat})) - iat should be
faker.date.recent()
- exp should be derived from iat (
I'll get this feature. This is going to be my first, so please be kind.
Welcome to the project. I assigned the issue to you.