@@ -91,62 +91,6 @@ class MockExecutionContext implements ExecutionContext {
91
91
}
92
92
}
93
93
94
- // Mock FormData to enable testing token endpoint
95
- class MockFormData implements FormData {
96
- private data : Map < string , string > = new Map ( ) ;
97
-
98
- append ( name : string , value : string | Blob , filename ?: string ) : void {
99
- this . data . set ( name , value . toString ( ) ) ;
100
- }
101
-
102
- delete ( name : string ) : void {
103
- this . data . delete ( name ) ;
104
- }
105
-
106
- get ( name : string ) : FormDataEntryValue | null {
107
- return this . data . get ( name ) || null ;
108
- }
109
-
110
- getAll ( name : string ) : FormDataEntryValue [ ] {
111
- const value = this . data . get ( name ) ;
112
- return value ? [ value ] : [ ] ;
113
- }
114
-
115
- has ( name : string ) : boolean {
116
- return this . data . has ( name ) ;
117
- }
118
-
119
- set ( name : string , value : string | Blob , filename ?: string ) : void {
120
- this . data . set ( name , value . toString ( ) ) ;
121
- }
122
-
123
- forEach ( callbackfn : ( value : FormDataEntryValue , key : string , parent : FormData ) => void ) : void {
124
- this . data . forEach ( ( value , key ) => callbackfn ( value , key , this ) ) ;
125
- }
126
-
127
- * entries ( ) : IterableIterator < [ string , FormDataEntryValue ] > {
128
- for ( const [ key , value ] of this . data . entries ( ) ) {
129
- yield [ key , value ] ;
130
- }
131
- }
132
-
133
- * keys ( ) : IterableIterator < string > {
134
- for ( const key of this . data . keys ( ) ) {
135
- yield key ;
136
- }
137
- }
138
-
139
- * values ( ) : IterableIterator < FormDataEntryValue > {
140
- for ( const value of this . data . values ( ) ) {
141
- yield value ;
142
- }
143
- }
144
-
145
- [ Symbol . iterator ] ( ) : IterableIterator < [ string , FormDataEntryValue ] > {
146
- return this . entries ( ) ;
147
- }
148
- }
149
-
150
94
// Simple API handler for testing
151
95
class TestApiHandler extends WorkerEntrypoint {
152
96
fetch ( request : Request ) {
@@ -606,21 +550,20 @@ describe('OAuthProvider', () => {
606
550
const code = url . searchParams . get ( 'code' ) ! ;
607
551
608
552
// Now exchange the code for tokens
609
- const formData = new MockFormData ( ) ;
610
- formData . append ( 'grant_type' , 'authorization_code' ) ;
611
- formData . append ( 'code' , code ) ;
612
- formData . append ( 'redirect_uri' , redirectUri ) ;
613
- formData . append ( 'client_id' , clientId ) ;
614
- formData . append ( 'client_secret' , clientSecret ) ;
615
-
616
- // Mock FormData in request
617
- vi . spyOn ( Request . prototype , 'formData' ) . mockResolvedValue ( formData as unknown as FormData ) ;
618
-
553
+ // Use URLSearchParams which is proper for application/x-www-form-urlencoded
554
+ const params = new URLSearchParams ( ) ;
555
+ params . append ( 'grant_type' , 'authorization_code' ) ;
556
+ params . append ( 'code' , code ) ;
557
+ params . append ( 'redirect_uri' , redirectUri ) ;
558
+ params . append ( 'client_id' , clientId ) ;
559
+ params . append ( 'client_secret' , clientSecret ) ;
560
+
561
+ // Use the URLSearchParams object as the body - correctly encoded for Content-Type: application/x-www-form-urlencoded
619
562
const tokenRequest = createMockRequest (
620
563
'https://example.com/oauth/token' ,
621
564
'POST' ,
622
565
{ 'Content-Type' : 'application/x-www-form-urlencoded' } ,
623
- formData as unknown as FormData
566
+ params . toString ( )
624
567
) ;
625
568
626
569
const tokenResponse = await oauthProvider . fetch ( tokenRequest , mockEnv , mockCtx ) ;
@@ -660,21 +603,18 @@ describe('OAuthProvider', () => {
660
603
const code = url . searchParams . get ( 'code' ) ! ;
661
604
662
605
// Now exchange the code without providing redirect_uri
663
- const formData = new MockFormData ( ) ;
664
- formData . append ( 'grant_type' , 'authorization_code' ) ;
665
- formData . append ( 'code' , code ) ;
606
+ const params = new URLSearchParams ( ) ;
607
+ params . append ( 'grant_type' , 'authorization_code' ) ;
608
+ params . append ( 'code' , code ) ;
666
609
// redirect_uri intentionally omitted
667
- formData . append ( 'client_id' , clientId ) ;
668
- formData . append ( 'client_secret' , clientSecret ) ;
669
-
670
- // Mock FormData in request
671
- vi . spyOn ( Request . prototype , 'formData' ) . mockResolvedValue ( formData as unknown as FormData ) ;
610
+ params . append ( 'client_id' , clientId ) ;
611
+ params . append ( 'client_secret' , clientSecret ) ;
672
612
673
613
const tokenRequest = createMockRequest (
674
614
'https://example.com/oauth/token' ,
675
615
'POST' ,
676
616
{ 'Content-Type' : 'application/x-www-form-urlencoded' } ,
677
- formData as unknown as FormData
617
+ params . toString ( )
678
618
) ;
679
619
680
620
const tokenResponse = await oauthProvider . fetch ( tokenRequest , mockEnv , mockCtx ) ;
@@ -729,22 +669,19 @@ describe('OAuthProvider', () => {
729
669
const code = url . searchParams . get ( 'code' ) ! ;
730
670
731
671
// Now exchange the code without providing redirect_uri
732
- const formData = new MockFormData ( ) ;
733
- formData . append ( 'grant_type' , 'authorization_code' ) ;
734
- formData . append ( 'code' , code ) ;
672
+ const params = new URLSearchParams ( ) ;
673
+ params . append ( 'grant_type' , 'authorization_code' ) ;
674
+ params . append ( 'code' , code ) ;
735
675
// redirect_uri intentionally omitted
736
- formData . append ( 'client_id' , clientId ) ;
737
- formData . append ( 'client_secret' , clientSecret ) ;
738
- formData . append ( 'code_verifier' , codeVerifier ) ;
739
-
740
- // Mock FormData in request
741
- vi . spyOn ( Request . prototype , 'formData' ) . mockResolvedValue ( formData as unknown as FormData ) ;
676
+ params . append ( 'client_id' , clientId ) ;
677
+ params . append ( 'client_secret' , clientSecret ) ;
678
+ params . append ( 'code_verifier' , codeVerifier ) ;
742
679
743
680
const tokenRequest = createMockRequest (
744
681
'https://example.com/oauth/token' ,
745
682
'POST' ,
746
683
{ 'Content-Type' : 'application/x-www-form-urlencoded' } ,
747
- formData as unknown as FormData
684
+ params . toString ( )
748
685
) ;
749
686
750
687
const tokenResponse = await oauthProvider . fetch ( tokenRequest , mockEnv , mockCtx ) ;
@@ -772,20 +709,18 @@ describe('OAuthProvider', () => {
772
709
const code = new URL ( location ) . searchParams . get ( 'code' ) ! ;
773
710
774
711
// Exchange for tokens
775
- const formData = new MockFormData ( ) ;
776
- formData . append ( 'grant_type' , 'authorization_code' ) ;
777
- formData . append ( 'code' , code ) ;
778
- formData . append ( 'redirect_uri' , redirectUri ) ;
779
- formData . append ( 'client_id' , clientId ) ;
780
- formData . append ( 'client_secret' , clientSecret ) ;
781
-
782
- vi . spyOn ( Request . prototype , 'formData' ) . mockResolvedValue ( formData as unknown as FormData ) ;
712
+ const params = new URLSearchParams ( ) ;
713
+ params . append ( 'grant_type' , 'authorization_code' ) ;
714
+ params . append ( 'code' , code ) ;
715
+ params . append ( 'redirect_uri' , redirectUri ) ;
716
+ params . append ( 'client_id' , clientId ) ;
717
+ params . append ( 'client_secret' , clientSecret ) ;
783
718
784
719
const tokenRequest = createMockRequest (
785
720
'https://example.com/oauth/token' ,
786
721
'POST' ,
787
722
{ 'Content-Type' : 'application/x-www-form-urlencoded' } ,
788
- formData as unknown as FormData
723
+ params . toString ( )
789
724
) ;
790
725
791
726
const tokenResponse = await oauthProvider . fetch ( tokenRequest , mockEnv , mockCtx ) ;
@@ -847,20 +782,18 @@ describe('OAuthProvider', () => {
847
782
const code = new URL ( location ) . searchParams . get ( 'code' ) ! ;
848
783
849
784
// Exchange for tokens
850
- const formData = new MockFormData ( ) ;
851
- formData . append ( 'grant_type' , 'authorization_code' ) ;
852
- formData . append ( 'code' , code ) ;
853
- formData . append ( 'redirect_uri' , redirectUri ) ;
854
- formData . append ( 'client_id' , clientId ) ;
855
- formData . append ( 'client_secret' , clientSecret ) ;
856
-
857
- vi . spyOn ( Request . prototype , 'formData' ) . mockResolvedValue ( formData as unknown as FormData ) ;
785
+ const params = new URLSearchParams ( ) ;
786
+ params . append ( 'grant_type' , 'authorization_code' ) ;
787
+ params . append ( 'code' , code ) ;
788
+ params . append ( 'redirect_uri' , redirectUri ) ;
789
+ params . append ( 'client_id' , clientId ) ;
790
+ params . append ( 'client_secret' , clientSecret ) ;
858
791
859
792
const tokenRequest = createMockRequest (
860
793
'https://example.com/oauth/token' ,
861
794
'POST' ,
862
795
{ 'Content-Type' : 'application/x-www-form-urlencoded' } ,
863
- formData as unknown as FormData
796
+ params . toString ( )
864
797
) ;
865
798
866
799
const tokenResponse = await oauthProvider . fetch ( tokenRequest , mockEnv , mockCtx ) ;
@@ -874,19 +807,17 @@ describe('OAuthProvider', () => {
874
807
875
808
it ( 'should issue new tokens with refresh token' , async ( ) => {
876
809
// Use the refresh token to get a new access token
877
- const formData = new MockFormData ( ) ;
878
- formData . append ( 'grant_type' , 'refresh_token' ) ;
879
- formData . append ( 'refresh_token' , refreshToken ) ;
880
- formData . append ( 'client_id' , clientId ) ;
881
- formData . append ( 'client_secret' , clientSecret ) ;
882
-
883
- vi . spyOn ( Request . prototype , 'formData' ) . mockResolvedValue ( formData as unknown as FormData ) ;
810
+ const params = new URLSearchParams ( ) ;
811
+ params . append ( 'grant_type' , 'refresh_token' ) ;
812
+ params . append ( 'refresh_token' , refreshToken ) ;
813
+ params . append ( 'client_id' , clientId ) ;
814
+ params . append ( 'client_secret' , clientSecret ) ;
884
815
885
816
const refreshRequest = createMockRequest (
886
817
'https://example.com/oauth/token' ,
887
818
'POST' ,
888
819
{ 'Content-Type' : 'application/x-www-form-urlencoded' } ,
889
- formData as unknown as FormData
820
+ params . toString ( )
890
821
) ;
891
822
892
823
const refreshResponse = await oauthProvider . fetch ( refreshRequest , mockEnv , mockCtx ) ;
@@ -913,39 +844,35 @@ describe('OAuthProvider', () => {
913
844
914
845
it ( 'should allow using the previous refresh token once' , async ( ) => {
915
846
// Use the refresh token to get a new access token (first refresh)
916
- const formData1 = new MockFormData ( ) ;
917
- formData1 . append ( 'grant_type' , 'refresh_token' ) ;
918
- formData1 . append ( 'refresh_token' , refreshToken ) ;
919
- formData1 . append ( 'client_id' , clientId ) ;
920
- formData1 . append ( 'client_secret' , clientSecret ) ;
921
-
922
- vi . spyOn ( Request . prototype , 'formData' ) . mockResolvedValueOnce ( formData1 as unknown as FormData ) ;
847
+ const params1 = new URLSearchParams ( ) ;
848
+ params1 . append ( 'grant_type' , 'refresh_token' ) ;
849
+ params1 . append ( 'refresh_token' , refreshToken ) ;
850
+ params1 . append ( 'client_id' , clientId ) ;
851
+ params1 . append ( 'client_secret' , clientSecret ) ;
923
852
924
853
const refreshRequest1 = createMockRequest (
925
854
'https://example.com/oauth/token' ,
926
855
'POST' ,
927
856
{ 'Content-Type' : 'application/x-www-form-urlencoded' } ,
928
- formData1 as unknown as FormData
857
+ params1 . toString ( )
929
858
) ;
930
859
931
860
const refreshResponse1 = await oauthProvider . fetch ( refreshRequest1 , mockEnv , mockCtx ) ;
932
861
const newTokens1 = await refreshResponse1 . json ( ) ;
933
862
const newRefreshToken = newTokens1 . refresh_token ;
934
863
935
864
// Now try to use the original refresh token again (simulating a retry after failure)
936
- const formData2 = new MockFormData ( ) ;
937
- formData2 . append ( 'grant_type' , 'refresh_token' ) ;
938
- formData2 . append ( 'refresh_token' , refreshToken ) ; // Original token
939
- formData2 . append ( 'client_id' , clientId ) ;
940
- formData2 . append ( 'client_secret' , clientSecret ) ;
941
-
942
- vi . spyOn ( Request . prototype , 'formData' ) . mockResolvedValueOnce ( formData2 as unknown as FormData ) ;
865
+ const params2 = new URLSearchParams ( ) ;
866
+ params2 . append ( 'grant_type' , 'refresh_token' ) ;
867
+ params2 . append ( 'refresh_token' , refreshToken ) ; // Original token
868
+ params2 . append ( 'client_id' , clientId ) ;
869
+ params2 . append ( 'client_secret' , clientSecret ) ;
943
870
944
871
const refreshRequest2 = createMockRequest (
945
872
'https://example.com/oauth/token' ,
946
873
'POST' ,
947
874
{ 'Content-Type' : 'application/x-www-form-urlencoded' } ,
948
- formData2 as unknown as FormData
875
+ params2 . toString ( )
949
876
) ;
950
877
951
878
const refreshResponse2 = await oauthProvider . fetch ( refreshRequest2 , mockEnv , mockCtx ) ;
@@ -1005,20 +932,18 @@ describe('OAuthProvider', () => {
1005
932
const code = new URL ( location ) . searchParams . get ( 'code' ) ! ;
1006
933
1007
934
// Exchange for tokens
1008
- const formData = new MockFormData ( ) ;
1009
- formData . append ( 'grant_type' , 'authorization_code' ) ;
1010
- formData . append ( 'code' , code ) ;
1011
- formData . append ( 'redirect_uri' , redirectUri ) ;
1012
- formData . append ( 'client_id' , clientId ) ;
1013
- formData . append ( 'client_secret' , clientSecret ) ;
1014
-
1015
- vi . spyOn ( Request . prototype , 'formData' ) . mockResolvedValue ( formData as unknown as FormData ) ;
935
+ const params = new URLSearchParams ( ) ;
936
+ params . append ( 'grant_type' , 'authorization_code' ) ;
937
+ params . append ( 'code' , code ) ;
938
+ params . append ( 'redirect_uri' , redirectUri ) ;
939
+ params . append ( 'client_id' , clientId ) ;
940
+ params . append ( 'client_secret' , clientSecret ) ;
1016
941
1017
942
const tokenRequest = createMockRequest (
1018
943
'https://example.com/oauth/token' ,
1019
944
'POST' ,
1020
945
{ 'Content-Type' : 'application/x-www-form-urlencoded' } ,
1021
- formData as unknown as FormData
946
+ params . toString ( )
1022
947
) ;
1023
948
1024
949
const tokenResponse = await oauthProvider . fetch ( tokenRequest , mockEnv , mockCtx ) ;
0 commit comments