Skip to content

Commit e3d8c37

Browse files
carrybitmasiddee
andauthored
Feature/custom http headers on ios (#607)
* Add support for sending additional http headers on iOS * Update readme with new config parameter * Correct implementation according to specification in tests * Add tests for iOS specific additionalHeaders parameter Also put some of the existing tests into correct group. * State validation rules in tests for additionalHeaders parameter * Validate additional headers * Correct readme * Format code * Updated Github config example to include additionalHeaders property Co-authored-by: Mansoor Siddeeq <mansoor@msiddeeq.com>
1 parent d3fcea2 commit e3d8c37

File tree

6 files changed

+245
-83
lines changed

6 files changed

+245
-83
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ with optional overrides.
129129
- **authorize** - (`{ [key: string]: value }`) headers to be passed during authorization request.
130130
- **token** - (`{ [key: string]: value }`) headers to be passed during token retrieval request.
131131
- **register** - (`{ [key: string]: value }`) headers to be passed during registration request.
132+
- **additionalHeaders** - (`{ [key: string]: value }`) _IOS_ you can specify additional headers to be passed for all authorize, refresh, and register requests.
132133
- **useNonce** - (`boolean`) _IOS_ (default: true) optionally allows not sending the nonce parameter, to support non-compliant providers
133134
- **usePKCE** - (`boolean`) (default: true) optionally allows not sending the code_challenge parameter and skipping PKCE code verification, to support non-compliant providers.
134135
- **skipCodeExchange** - (`boolean`) (default: false) just return the authorization response, instead of automatically exchanging the authorization code. This is useful if this exchange needs to be done manually (not client-side)

docs/config-examples/github.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
# GitHub
22

3-
** This is Android Only **
4-
5-
Read more about iOS restrictions [here](https://github.com/FormidableLabs/react-native-app-auth/issues/194).
6-
73
Go to [OAuth Apps](https://github.com/settings/developers) to create your app.
84

95
For the Authorization callback URL, choose something like `com.myapp://oauthredirect` and ensure you use `com.myapp` in your `appAuthRedirectScheme` in `android/app/build.gradle`.
@@ -14,6 +10,7 @@ const config = {
1410
clientId: '<client-id>',
1511
clientSecret: '<client-secret>',
1612
scopes: ['identity'],
13+
additionalHeaders: { 'Accept': 'application/json' },
1714
serviceConfiguration: {
1815
authorizationEndpoint: 'https://github.com/login/oauth/authorize',
1916
tokenEndpoint: 'https://github.com/login/oauth/access_token',

index.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ type CustomHeaders = {
2121
register?: Record<string, string>;
2222
};
2323

24+
type AdditionalHeaders = Record<string, string>;
25+
2426
interface BuiltInRegistrationParameters {
2527
client_name?: string;
2628
logo_uri?: string;
@@ -38,6 +40,7 @@ export type RegistrationConfiguration = BaseConfiguration & {
3840
additionalParameters?: BuiltInRegistrationParameters & { [name: string]: string };
3941
dangerouslyAllowInsecureHttpRequests?: boolean;
4042
customHeaders?: CustomHeaders;
43+
additionalHeaders?: AdditionalHeaders;
4144
};
4245

4346
export interface RegistrationResponse {
@@ -69,6 +72,7 @@ export type AuthConfiguration = BaseAuthConfiguration & {
6972
clientAuthMethod?: 'basic' | 'post';
7073
dangerouslyAllowInsecureHttpRequests?: boolean;
7174
customHeaders?: CustomHeaders;
75+
additionalHeaders?: AdditionalHeaders;
7276
useNonce?: boolean;
7377
usePKCE?: boolean;
7478
warmAndPrefetchChrome?: boolean;

index.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ const validateHeaders = headers => {
5555
});
5656
};
5757

58+
const validateAdditionalHeaders = headers => {
59+
if (!headers) {
60+
return;
61+
}
62+
63+
const errorMessage = 'Config error: additionalHeaders must be { [key: string]: string }';
64+
65+
invariant(typeof headers === 'object', errorMessage);
66+
invariant(
67+
Object.values(headers).filter(key => typeof key !== 'string').length === 0,
68+
errorMessage
69+
);
70+
};
71+
5872
export const prefetchConfiguration = async ({
5973
warmAndPrefetchChrome,
6074
issuer,
@@ -97,9 +111,12 @@ export const register = ({
97111
serviceConfiguration,
98112
dangerouslyAllowInsecureHttpRequests = false,
99113
customHeaders,
114+
additionalHeaders,
100115
}) => {
101116
validateIssuerOrServiceConfigurationRegistrationEndpoint(issuer, serviceConfiguration);
102117
validateHeaders(customHeaders);
118+
validateAdditionalHeaders(additionalHeaders);
119+
103120
invariant(
104121
Array.isArray(redirectUrls) && redirectUrls.every(url => typeof url === 'string'),
105122
'Config error: redirectUrls must be an Array of strings'
@@ -139,6 +156,10 @@ export const register = ({
139156
nativeMethodArguments.push(customHeaders);
140157
}
141158

159+
if (Platform.OS === 'ios') {
160+
nativeMethodArguments.push(additionalHeaders);
161+
}
162+
142163
return RNAppAuth.register(...nativeMethodArguments);
143164
};
144165

@@ -155,12 +176,14 @@ export const authorize = ({
155176
clientAuthMethod = 'basic',
156177
dangerouslyAllowInsecureHttpRequests = false,
157178
customHeaders,
179+
additionalHeaders,
158180
skipCodeExchange = false,
159181
}) => {
160182
validateIssuerOrServiceConfigurationEndpoints(issuer, serviceConfiguration);
161183
validateClientId(clientId);
162184
validateRedirectUrl(redirectUrl);
163185
validateHeaders(customHeaders);
186+
validateAdditionalHeaders(additionalHeaders);
164187
// TODO: validateAdditionalParameters
165188

166189
const nativeMethodArguments = [
@@ -182,6 +205,7 @@ export const authorize = ({
182205
}
183206

184207
if (Platform.OS === 'ios') {
208+
nativeMethodArguments.push(additionalHeaders);
185209
nativeMethodArguments.push(useNonce);
186210
nativeMethodArguments.push(usePKCE);
187211
}
@@ -201,13 +225,15 @@ export const refresh = (
201225
clientAuthMethod = 'basic',
202226
dangerouslyAllowInsecureHttpRequests = false,
203227
customHeaders,
228+
additionalHeaders,
204229
},
205230
{ refreshToken }
206231
) => {
207232
validateIssuerOrServiceConfigurationEndpoints(issuer, serviceConfiguration);
208233
validateClientId(clientId);
209234
validateRedirectUrl(redirectUrl);
210235
validateHeaders(customHeaders);
236+
validateAdditionalHeaders(additionalHeaders);
211237
invariant(refreshToken, 'Please pass in a refresh token');
212238
// TODO: validateAdditionalParameters
213239

@@ -228,6 +254,10 @@ export const refresh = (
228254
nativeMethodArguments.push(customHeaders);
229255
}
230256

257+
if (Platform.OS === 'ios') {
258+
nativeMethodArguments.push(additionalHeaders);
259+
}
260+
231261
return RNAppAuth.refresh(...nativeMethodArguments);
232262
};
233263

0 commit comments

Comments
 (0)