@pagopa/io-react-native-jwt 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +145 -0
  3. package/android/build.gradle +97 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/java/com/pagopa/ioreactnativejwt/IoReactNativeJwtModule.kt +114 -0
  7. package/android/src/main/java/com/pagopa/ioreactnativejwt/IoReactNativeJwtPackage.kt +17 -0
  8. package/android/src/main/java/com/pagopa/ioreactnativejwt/Utils.kt +95 -0
  9. package/ios/ASN1DERParsing.swift +226 -0
  10. package/ios/IoReactNativeJwt-Bridging-Header.h +2 -0
  11. package/ios/IoReactNativeJwt.mm +28 -0
  12. package/ios/IoReactNativeJwt.swift +156 -0
  13. package/ios/IoReactNativeJwt.xcodeproj/project.pbxproj +283 -0
  14. package/lib/commonjs/algorithms.js +39 -0
  15. package/lib/commonjs/algorithms.js.map +1 -0
  16. package/lib/commonjs/hash.js +17 -0
  17. package/lib/commonjs/hash.js.map +1 -0
  18. package/lib/commonjs/index.js +194 -0
  19. package/lib/commonjs/index.js.map +1 -0
  20. package/lib/commonjs/jwt_claims_set.js +112 -0
  21. package/lib/commonjs/jwt_claims_set.js.map +1 -0
  22. package/lib/commonjs/produce.js +140 -0
  23. package/lib/commonjs/produce.js.map +1 -0
  24. package/lib/commonjs/sign.js +159 -0
  25. package/lib/commonjs/sign.js.map +1 -0
  26. package/lib/commonjs/types.js +2 -0
  27. package/lib/commonjs/types.js.map +1 -0
  28. package/lib/commonjs/unsecured.js +118 -0
  29. package/lib/commonjs/unsecured.js.map +1 -0
  30. package/lib/commonjs/utils/asn1.js +37 -0
  31. package/lib/commonjs/utils/asn1.js.map +1 -0
  32. package/lib/commonjs/utils/base64.js +43 -0
  33. package/lib/commonjs/utils/base64.js.map +1 -0
  34. package/lib/commonjs/utils/errors.js +214 -0
  35. package/lib/commonjs/utils/errors.js.map +1 -0
  36. package/lib/commonjs/utils/is_object.js +23 -0
  37. package/lib/commonjs/utils/is_object.js.map +1 -0
  38. package/lib/commonjs/utils/proxy.js +17 -0
  39. package/lib/commonjs/utils/proxy.js.map +1 -0
  40. package/lib/commonjs/utils/secs.js +61 -0
  41. package/lib/commonjs/utils/secs.js.map +1 -0
  42. package/lib/module/algorithms.js +29 -0
  43. package/lib/module/algorithms.js.map +1 -0
  44. package/lib/module/hash.js +11 -0
  45. package/lib/module/hash.js.map +1 -0
  46. package/lib/module/index.js +115 -0
  47. package/lib/module/index.js.map +1 -0
  48. package/lib/module/jwt_claims_set.js +103 -0
  49. package/lib/module/jwt_claims_set.js.map +1 -0
  50. package/lib/module/produce.js +131 -0
  51. package/lib/module/produce.js.map +1 -0
  52. package/lib/module/sign.js +153 -0
  53. package/lib/module/sign.js.map +1 -0
  54. package/lib/module/types.js +2 -0
  55. package/lib/module/types.js.map +1 -0
  56. package/lib/module/unsecured.js +110 -0
  57. package/lib/module/unsecured.js.map +1 -0
  58. package/lib/module/utils/asn1.js +31 -0
  59. package/lib/module/utils/asn1.js.map +1 -0
  60. package/lib/module/utils/base64.js +36 -0
  61. package/lib/module/utils/base64.js.map +1 -0
  62. package/lib/module/utils/errors.js +200 -0
  63. package/lib/module/utils/errors.js.map +1 -0
  64. package/lib/module/utils/is_object.js +17 -0
  65. package/lib/module/utils/is_object.js.map +1 -0
  66. package/lib/module/utils/proxy.js +10 -0
  67. package/lib/module/utils/proxy.js.map +1 -0
  68. package/lib/module/utils/secs.js +53 -0
  69. package/lib/module/utils/secs.js.map +1 -0
  70. package/lib/typescript/algorithms.d.ts +5 -0
  71. package/lib/typescript/algorithms.d.ts.map +1 -0
  72. package/lib/typescript/hash.d.ts +5 -0
  73. package/lib/typescript/hash.d.ts.map +1 -0
  74. package/lib/typescript/index.d.ts +93 -0
  75. package/lib/typescript/index.d.ts.map +1 -0
  76. package/lib/typescript/jwt_claims_set.d.ts +4 -0
  77. package/lib/typescript/jwt_claims_set.d.ts.map +1 -0
  78. package/lib/typescript/produce.d.ts +55 -0
  79. package/lib/typescript/produce.d.ts.map +1 -0
  80. package/lib/typescript/sign.d.ts +61 -0
  81. package/lib/typescript/sign.d.ts.map +1 -0
  82. package/lib/typescript/types.d.ts +172 -0
  83. package/lib/typescript/types.d.ts.map +1 -0
  84. package/lib/typescript/unsecured.d.ts +64 -0
  85. package/lib/typescript/unsecured.d.ts.map +1 -0
  86. package/lib/typescript/utils/asn1.d.ts +2 -0
  87. package/lib/typescript/utils/asn1.d.ts.map +1 -0
  88. package/lib/typescript/utils/base64.d.ts +4 -0
  89. package/lib/typescript/utils/base64.d.ts.map +1 -0
  90. package/lib/typescript/utils/errors.d.ts +157 -0
  91. package/lib/typescript/utils/errors.d.ts.map +1 -0
  92. package/lib/typescript/utils/is_object.d.ts +2 -0
  93. package/lib/typescript/utils/is_object.d.ts.map +1 -0
  94. package/lib/typescript/utils/proxy.d.ts +2 -0
  95. package/lib/typescript/utils/proxy.d.ts.map +1 -0
  96. package/lib/typescript/utils/secs.d.ts +4 -0
  97. package/lib/typescript/utils/secs.d.ts.map +1 -0
  98. package/package.json +170 -0
  99. package/pagopa-io-react-native-jwt.podspec +44 -0
  100. package/src/algorithms.ts +46 -0
  101. package/src/hash.ts +10 -0
  102. package/src/index.tsx +120 -0
  103. package/src/jwt_claims_set.ts +194 -0
  104. package/src/produce.ts +109 -0
  105. package/src/sign.ts +180 -0
  106. package/src/types.ts +203 -0
  107. package/src/unsecured.ts +127 -0
  108. package/src/utils/asn1.ts +36 -0
  109. package/src/utils/base64.ts +37 -0
  110. package/src/utils/errors.ts +206 -0
  111. package/src/utils/is_object.ts +20 -0
  112. package/src/utils/proxy.ts +15 -0
  113. package/src/utils/secs.ts +58 -0
package/src/sign.ts ADDED
@@ -0,0 +1,180 @@
1
+ import { JOSENotSupported, JWSInvalid, JWTInvalid } from './utils/errors';
2
+ import type {
3
+ CompactJWSHeaderParameters,
4
+ JWTDecodeResult,
5
+ JWTPayload,
6
+ } from './types';
7
+ import { ProduceJWT } from './produce';
8
+ import { decodeBase64, encodeBase64, removePadding } from './utils/base64';
9
+ import { isAlgSupported } from './algorithms';
10
+
11
+ import { derToJose } from './utils/asn1';
12
+
13
+ /**
14
+ * The SignJWT class is used to build and sign Compact JWS formatted JSON Web Tokens.
15
+ *
16
+ * @example Usage with a given signature
17
+ *
18
+ * ```js
19
+ * const alg = 'RS256'
20
+ * const signature = 'Axy0....'
21
+ *
22
+ * const jwt = new SignJWT({ 'urn:example:claim': true })
23
+ * .setProtectedHeader({ alg })
24
+ * .setIssuedAt()
25
+ * .setIssuer('urn:example:issuer')
26
+ * .setAudience('urn:example:audience')
27
+ * .setExpirationTime('2h')
28
+ * .sign(signature)
29
+ *
30
+ * console.log(jwt)
31
+ * ```
32
+ */
33
+ export class SignJWT extends ProduceJWT {
34
+ private _protectedHeader!: CompactJWSHeaderParameters;
35
+
36
+ /**
37
+ * Sets the JWS Protected Header on the SignJWT object.
38
+ *
39
+ * @param protectedHeader JWS Protected Header. Must contain an "alg" (JWS Algorithm) property.
40
+ */
41
+ setProtectedHeader(protectedHeader: CompactJWSHeaderParameters) {
42
+ if (protectedHeader.alg && isAlgSupported(protectedHeader.alg)) {
43
+ this._protectedHeader = protectedHeader;
44
+ return this;
45
+ }
46
+ throw new JOSENotSupported('Unsupported "alg" value');
47
+ }
48
+
49
+ /**
50
+ * Return a JWT without signature (`header.payload`) to sign.
51
+ *
52
+ */
53
+ toSign(): string {
54
+ if (!this._protectedHeader || !this._protectedHeader.alg) {
55
+ throw new JWSInvalid(
56
+ 'Missing signature algorithm. Specify the `alg` field'
57
+ );
58
+ }
59
+ const protectedHeader = encodeBase64(JSON.stringify(this._protectedHeader));
60
+ const payload = encodeBase64(JSON.stringify(this._payload));
61
+ if (payload && protectedHeader) {
62
+ return `${protectedHeader}.${payload}`;
63
+ } else {
64
+ throw new JWSInvalid();
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Append signature to unsigned JWT.
70
+ * For an ECDSA signature it is required that this is in ASN.1/DER encoded format.
71
+ * The same format used by the TEE. Conversion to JWS is handled automatically.
72
+ *
73
+ * @param jwtWithoutSignature
74
+ * @param signature
75
+ */
76
+ static async appendSignature(
77
+ jwtWithoutSignature: string,
78
+ signature: string
79
+ ): Promise<string> {
80
+ if (
81
+ typeof jwtWithoutSignature !== 'string' ||
82
+ typeof signature !== 'string'
83
+ ) {
84
+ throw new JWTInvalid('JWS must be a string');
85
+ }
86
+ if (signature === '') throw new JWSInvalid('Invalid signature');
87
+
88
+ const jwtDecoded = SignJWT.decodeJwtWithoutSignature(jwtWithoutSignature);
89
+ const alg = jwtDecoded.header.alg;
90
+ try {
91
+ const encodedJws = await derToJose(signature, alg);
92
+ return `${jwtWithoutSignature}.${encodedJws}`;
93
+ } catch {
94
+ const encodedJws = removePadding(signature);
95
+ return `${jwtWithoutSignature}.${encodedJws}`;
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Decodes a JWT without signature
101
+ *
102
+ * @param jwtWithoutSignature JWT to sign that needs to be decoded.
103
+ */
104
+ static decodeJwtWithoutSignature(jwtWithoutSignature: string): {
105
+ payload: JWTPayload;
106
+ header: CompactJWSHeaderParameters;
107
+ } {
108
+ if (typeof jwtWithoutSignature !== 'string') {
109
+ throw new JWTInvalid('JWT must be a string');
110
+ }
111
+ const {
112
+ 0: encodedHeader,
113
+ 1: encodedPayload,
114
+ length,
115
+ } = jwtWithoutSignature.split('.');
116
+
117
+ let header: CompactJWSHeaderParameters;
118
+ try {
119
+ let decoded = decodeBase64(encodedHeader!);
120
+ header = JSON.parse(decoded);
121
+ if (!header.alg || !isAlgSupported(header.alg)) {
122
+ throw new JOSENotSupported('Unsupported "alg" value');
123
+ }
124
+ } catch {
125
+ throw new JWTInvalid('Unable to decode JWT header');
126
+ }
127
+
128
+ if (length !== 2 || encodedPayload === '') {
129
+ throw new JWTInvalid('Invalid JWT to sign');
130
+ }
131
+
132
+ let decodedPayload = decodeBase64(encodedPayload!);
133
+ const payload = JSON.parse(decodedPayload);
134
+
135
+ return {
136
+ payload,
137
+ header,
138
+ };
139
+ }
140
+
141
+ /**
142
+ * Decodes a JWT without signature
143
+ *
144
+ * @param jwtWithoutSignature JWT to sign that needs to be decoded.
145
+ */
146
+ static decode(jwt: string): JWTDecodeResult {
147
+ if (typeof jwt !== 'string') {
148
+ throw new JWTInvalid('JWT must be a string');
149
+ }
150
+ const {
151
+ 0: encodedHeader,
152
+ 1: encodedPayload,
153
+ 2: signature,
154
+ length,
155
+ } = jwt.split('.');
156
+
157
+ let protectedHeader: CompactJWSHeaderParameters;
158
+ try {
159
+ let decoded = decodeBase64(encodedHeader!);
160
+ protectedHeader = JSON.parse(decoded);
161
+ if (!protectedHeader.alg || !isAlgSupported(protectedHeader.alg)) {
162
+ throw new JOSENotSupported('Unsupported "alg" value');
163
+ }
164
+ } catch {
165
+ throw new JWTInvalid('Unable to decode JWT header');
166
+ }
167
+
168
+ if (length !== 3 || encodedPayload === '' || signature === '') {
169
+ throw new JWTInvalid('Invalid JWT');
170
+ }
171
+
172
+ let decodedPayload = decodeBase64(encodedPayload!);
173
+ const payload = JSON.parse(decodedPayload);
174
+
175
+ return {
176
+ payload,
177
+ protectedHeader,
178
+ };
179
+ }
180
+ }
package/src/types.ts ADDED
@@ -0,0 +1,203 @@
1
+ export interface JWTDecodeResult {
2
+ /** JWT Claims Set. */
3
+ payload: JWTPayload;
4
+
5
+ /** JWS Protected Header. */
6
+ protectedHeader: JWSHeaderParameters;
7
+ }
8
+
9
+ /**
10
+ * JSON Web Key ({@link https://www.rfc-editor.org/rfc/rfc7517 JWK}). "RSA", "EC", "OKP", and "oct"
11
+ * key types are supported.
12
+ */
13
+ export interface JWK {
14
+ /** JWK "alg" (Algorithm) Parameter. */
15
+ 'alg'?: string;
16
+ 'crv'?: string;
17
+ 'd'?: string;
18
+ 'dp'?: string;
19
+ 'dq'?: string;
20
+ 'e'?: string;
21
+ /** JWK "ext" (Extractable) Parameter. */
22
+ 'ext'?: boolean;
23
+ 'k'?: string;
24
+ /** JWK "key_ops" (Key Operations) Parameter. */
25
+ 'key_ops'?: string[];
26
+ /** JWK "kid" (Key ID) Parameter. */
27
+ 'kid'?: string;
28
+ /** JWK "kty" (Key Type) Parameter.
29
+ * This attribute is required to discriminate the
30
+ * type of EC/RSA algorithm */
31
+ 'kty': string;
32
+ 'n'?: string;
33
+ 'oth'?: Array<{
34
+ d?: string;
35
+ r?: string;
36
+ t?: string;
37
+ }>;
38
+ 'p'?: string;
39
+ 'q'?: string;
40
+ 'qi'?: string;
41
+ /** JWK "use" (Public Key Use) Parameter. */
42
+ 'use'?: string;
43
+ 'x'?: string;
44
+ 'y'?: string;
45
+ /** JWK "x5c" (X.509 Certificate Chain) Parameter. */
46
+ 'x5c'?: string[];
47
+ /** JWK "x5t" (X.509 Certificate SHA-1 Thumbprint) Parameter. */
48
+ 'x5t'?: string;
49
+ /** "x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Parameter. */
50
+ 'x5t#S256'?: string;
51
+ /** JWK "x5u" (X.509 URL) Parameter. */
52
+ 'x5u'?: string;
53
+
54
+ [propName: string]: unknown;
55
+ }
56
+
57
+ export interface JoseHeaderParameters {
58
+ /** "kid" (Key ID) Header Parameter. */
59
+ kid?: string;
60
+
61
+ /** "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter. */
62
+ x5t?: string;
63
+
64
+ /** "x5c" (X.509 Certificate Chain) Header Parameter. */
65
+ x5c?: string[];
66
+
67
+ /** "x5u" (X.509 URL) Header Parameter. */
68
+ x5u?: string;
69
+
70
+ /** "jku" (JWK Set URL) Header Parameter. */
71
+ jku?: string;
72
+
73
+ /** "jwk" (JSON Web Key) Header Parameter. */
74
+ jwk?: Pick<JWK, 'kty' | 'crv' | 'x' | 'y' | 'e' | 'n'>;
75
+
76
+ /** "typ" (Type) Header Parameter. */
77
+ typ?: string;
78
+
79
+ /** "cty" (Content Type) Header Parameter. */
80
+ cty?: string;
81
+ }
82
+
83
+ /** Recognized JWS Header Parameters, any other Header Members may also be present. */
84
+ export interface JWSHeaderParameters extends JoseHeaderParameters {
85
+ /** JWS "alg" (Algorithm) Header Parameter. */
86
+ alg?: string;
87
+
88
+ /**
89
+ * This JWS Extension Header Parameter modifies the JWS Payload representation and the JWS Signing
90
+ * Input computation as per {@link https://www.rfc-editor.org/rfc/rfc7797 RFC7797}.
91
+ */
92
+ b64?: boolean;
93
+
94
+ /** JWS "crit" (Critical) Header Parameter. */
95
+ crit?: string[];
96
+
97
+ /** Any other JWS Header member. */
98
+ [propName: string]: unknown;
99
+ }
100
+
101
+ /** Recognized Compact JWS Header Parameters, any other Header Members may also be present. */
102
+ export interface CompactJWSHeaderParameters extends JWSHeaderParameters {
103
+ alg: string;
104
+ }
105
+
106
+ /** Recognized JWT Claims Set members, any other members may also be present. */
107
+ export interface JWTPayload {
108
+ /**
109
+ * JWT Issuer
110
+ *
111
+ * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.1 RFC7519#section-4.1.1}
112
+ */
113
+ iss?: string;
114
+
115
+ /**
116
+ * JWT Subject
117
+ *
118
+ * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.2 RFC7519#section-4.1.2}
119
+ */
120
+ sub?: string;
121
+
122
+ /**
123
+ * JWT Audience
124
+ *
125
+ * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3 RFC7519#section-4.1.3}
126
+ */
127
+ aud?: string | string[];
128
+
129
+ /**
130
+ * JWT ID
131
+ *
132
+ * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.7 RFC7519#section-4.1.7}
133
+ */
134
+ jti?: string;
135
+
136
+ /**
137
+ * JWT Not Before
138
+ *
139
+ * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.5 RFC7519#section-4.1.5}
140
+ */
141
+ nbf?: number;
142
+
143
+ /**
144
+ * JWT Expiration Time
145
+ *
146
+ * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4 RFC7519#section-4.1.4}
147
+ */
148
+ exp?: number;
149
+
150
+ /**
151
+ * JWT Issued At
152
+ *
153
+ * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 RFC7519#section-4.1.6}
154
+ */
155
+ iat?: number;
156
+
157
+ /** Any other JWT Claim Set member. */
158
+ [propName: string]: unknown;
159
+ }
160
+
161
+ /** JWT Claims Set verification options. */
162
+ export interface JWTClaimVerificationOptions {
163
+ /** Expected JWT "aud" (Audience) Claim value(s). */
164
+ audience?: string | string[];
165
+
166
+ /**
167
+ * Expected clock tolerance
168
+ *
169
+ * - In seconds when number (e.g. 5)
170
+ * - Parsed as seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours").
171
+ */
172
+ clockTolerance?: string | number;
173
+
174
+ /** Expected JWT "iss" (Issuer) Claim value(s). */
175
+ issuer?: string | string[];
176
+
177
+ /**
178
+ * Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value.
179
+ *
180
+ * - In seconds when number (e.g. 5)
181
+ * - Parsed as seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours").
182
+ */
183
+ maxTokenAge?: string | number;
184
+
185
+ /** Expected JWT "sub" (Subject) Claim value. */
186
+ subject?: string;
187
+
188
+ /** Expected JWT "typ" (Type) Header Parameter value. */
189
+ typ?: string;
190
+
191
+ /** Date to use when comparing NumericDate claims, defaults to `new Date()`. */
192
+ currentDate?: Date;
193
+
194
+ /**
195
+ * Array of required Claim Names that must be present in the JWT Claims Set. Default is that: if
196
+ * the {@link JWTClaimVerificationOptions.issuer issuer option} is set, then "iss" must be present;
197
+ * if the {@link JWTClaimVerificationOptions.audience audience option} is set, then "aud" must be
198
+ * present; if the {@link JWTClaimVerificationOptions.subject subject option} is set, then "sub"
199
+ * must be present; if the {@link JWTClaimVerificationOptions.maxTokenAge maxTokenAge option} is
200
+ * set, then "iat" must be present.
201
+ */
202
+ requiredClaims?: string[];
203
+ }
@@ -0,0 +1,127 @@
1
+ import type {
2
+ JWSHeaderParameters,
3
+ JWTClaimVerificationOptions,
4
+ JWTPayload,
5
+ } from './types';
6
+
7
+ import { JWTInvalid } from './utils/errors';
8
+ import jwtPayload from './jwt_claims_set';
9
+ import { ProduceJWT } from './produce';
10
+ import { decodeBase64, encodeBase64 } from './utils/base64';
11
+
12
+ export interface UnsecuredResult {
13
+ payload: JWTPayload;
14
+ header: JWSHeaderParameters;
15
+ }
16
+
17
+ /**
18
+ * The UnsecuredJWT class is a utility for dealing with `{ "alg": "none" }` Unsecured JWTs.
19
+ *
20
+ * @example Encoding
21
+ *
22
+ * ```js
23
+ * const unsecuredJwt = new UnsecuredJWT({ 'urn:example:claim': true })
24
+ * .setIssuedAt()
25
+ * .setIssuer('urn:example:issuer')
26
+ * .setAudience('urn:example:audience')
27
+ * .setExpirationTime('2h')
28
+ * .encode()
29
+ *
30
+ * console.log(unsecuredJwt)
31
+ * ```
32
+ *
33
+ * @example Decoding
34
+ *
35
+ * ```js
36
+ * const payload = UnsecuredJWT.decode(jwt, {
37
+ * issuer: 'urn:example:issuer',
38
+ * audience: 'urn:example:audience',
39
+ * })
40
+ *
41
+ * console.log(payload)
42
+ * ```
43
+ * * @example JWT content ToSign
44
+ *
45
+ * ```js
46
+ * const jwtToSign = new UnsecuredJWT({ 'urn:example:claim': true })
47
+ * .setIssuedAt()
48
+ * .setIssuer('urn:example:issuer')
49
+ * .setAudience('urn:example:audience')
50
+ * .setExpirationTime('2h')
51
+ * .toSign()
52
+ *
53
+ * console.log(jwtToSign)
54
+ * ```
55
+ */
56
+ export class UnsecuredJWT extends ProduceJWT {
57
+ /** Encodes the Unsecured JWT. */
58
+ encode(): string {
59
+ const header = encodeBase64(JSON.stringify({ alg: 'none' }));
60
+ const payload = encodeBase64(JSON.stringify(this._payload));
61
+
62
+ return `${header}.${payload}.`;
63
+ }
64
+
65
+ /**
66
+ * Decodes an unsecured JWT.
67
+ *
68
+ * @param jwt Unsecured JWT to decode the payload of.
69
+ * @param options JWT Claims Set validation options.
70
+ */
71
+ static decode(
72
+ jwt: string,
73
+ options?: JWTClaimVerificationOptions
74
+ ): UnsecuredResult {
75
+ if (typeof jwt !== 'string') {
76
+ throw new JWTInvalid('Unsecured JWT must be a string');
77
+ }
78
+ const {
79
+ 0: encodedHeader,
80
+ 1: encodedPayload,
81
+ 2: signature,
82
+ length,
83
+ } = jwt.split('.');
84
+
85
+ if (length !== 3 || signature !== '' || !encodedPayload) {
86
+ throw new JWTInvalid('Invalid Unsecured JWT');
87
+ }
88
+
89
+ let header: JWSHeaderParameters;
90
+ try {
91
+ let decoded = decodeBase64(encodedHeader!);
92
+ header = JSON.parse(decoded);
93
+ if (header.alg !== 'none') throw new Error();
94
+ } catch {
95
+ throw new JWTInvalid('Invalid Unsecured JWT');
96
+ }
97
+
98
+ let payload = UnsecuredJWT.decodePayload(encodedPayload, options);
99
+
100
+ return { payload, header };
101
+ }
102
+
103
+ /**
104
+ * Decodes an unsecured JWT payload.
105
+ *
106
+ * @param jwt Unsecured JWT payload to decode.
107
+ * @param options JWT Claims Set validation options.
108
+ */
109
+ static decodePayload(
110
+ jwt: string,
111
+ options?: JWTClaimVerificationOptions
112
+ ): JWTPayload {
113
+ if (typeof jwt !== 'string') {
114
+ throw new JWTInvalid('Unsecured JWT must be a string');
115
+ }
116
+ const { 0: encodedPayload, length } = jwt.split('.');
117
+
118
+ if (length !== 1 || encodedPayload === '') {
119
+ throw new JWTInvalid('Invalid Unsecured JWT');
120
+ }
121
+
122
+ let decodedPayload = decodeBase64(encodedPayload!);
123
+ const payload = jwtPayload({}, JSON.parse(decodedPayload), options);
124
+
125
+ return payload;
126
+ }
127
+ }
@@ -0,0 +1,36 @@
1
+ import { getCoordinateOctetLength, getKtyFromAlg } from '../algorithms';
2
+ import { IoReactNativeJwt } from './proxy';
3
+ import { removePadding } from './base64';
4
+ import { JOSENotSupported } from './errors';
5
+
6
+ /*
7
+ * Transcodes the JCA ASN.1/DER-encoded signature into the concatenated R + S format expected by ECDSA JWS.
8
+ * Returns a base64 url encoded String.
9
+ *
10
+ * @example Usage with an ASN.1/DER-encoded
11
+ *
12
+ * ```js
13
+ * const asn1Signature = 'Yw1xTT....'
14
+ * const plainSignature = await derToJose(asn1Signature, "ECDSA256")
15
+ *
16
+ * ```
17
+ *
18
+ * @param asn1Signature ASN.1/DER-encoded signature
19
+ * @param alg Algorithm used to sign
20
+ */
21
+ export const derToJose = async (
22
+ asn1Signature: string,
23
+ alg: string
24
+ ): Promise<string> => {
25
+ const kty = getKtyFromAlg(alg);
26
+ if (kty === 'EC') {
27
+ const unpackedJws = await IoReactNativeJwt.unpackBerEncodedASN1(
28
+ asn1Signature,
29
+ getCoordinateOctetLength(alg)
30
+ );
31
+ const encodedJws = removePadding(unpackedJws);
32
+ return encodedJws;
33
+ } else {
34
+ throw new JOSENotSupported('Unsupported "alg" value');
35
+ }
36
+ };
@@ -0,0 +1,37 @@
1
+ import { btoa, atob } from 'abab';
2
+ import { JOSEError } from './errors';
3
+
4
+ /*
5
+ * In Base64 encoding, the length of an output-encoded String
6
+ * must be a multiple of four. If necessary, the encoder adds
7
+ * one or two padding characters (=) at the end of the output
8
+ * as needed in order to meet this requirement.
9
+ *
10
+ * JWTs make use of the base64url encoding as defined in RFC 4648.
11
+ * As allowed by Section 3.2 of the RFC, this specification mandates
12
+ * that base64url encoding when used with JWTs MUST NOT use padding.
13
+ * The reason for this restriction is that the padding character
14
+ * ('=') is not URL safe.
15
+ */
16
+ export function encodeBase64(value: string): string {
17
+ let encoded = btoa(value);
18
+ if (encoded) {
19
+ return removePadding(encoded);
20
+ } else {
21
+ throw new JOSEError('Unable to encode string to base64');
22
+ }
23
+ }
24
+
25
+ export function decodeBase64(value: string): string {
26
+ let decoded = atob(value);
27
+ if (decoded) {
28
+ return decoded;
29
+ } else {
30
+ throw new JOSEError('Unable to decode base64 string');
31
+ }
32
+ }
33
+
34
+ export function removePadding(encoded: string): string {
35
+ // eslint-disable-next-line no-div-regex
36
+ return encoded.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
37
+ }