Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions example/capacitor/src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ function isPlatformWeb(): boolean {
return Capacitor.getPlatform() === "web";
}

async function myfetch(
input: URL | RequestInfo,
init?: RequestInit
): Promise<Response> {
const request = new Request(input, init);
request.headers.set("x-custom-header", "42");
return fetch(request);
}

function AuthgearDemo() {
const [isAlertOpen, setIsAlertOpen] = useState(false);
const [alertHeader, setAlertHeader] = useState("");
Expand Down Expand Up @@ -228,6 +237,7 @@ function AuthgearDemo() {
endpoint,
sessionType: "refresh_token",
isSSOEnabled,
fetch: myfetch,
});
} else {
await authgearCapacitor.configure({
Expand All @@ -246,6 +256,7 @@ function AuthgearDemo() {
: undefined,
isSSOEnabled,
preAuthenticatedURLEnabled,
fetch: myfetch,
});
}
await postConfigure();
Expand Down
11 changes: 11 additions & 0 deletions example/reactnative/src/screens/MainScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ const biometricOptions: BiometricOptions = {
},
};

async function myfetch(
input: URL | RequestInfo,
init?: RequestInit,
): Promise<Response> {
// @ts-expect-error The Request class in React Native does not take URL in the first argument.
const request = new Request(input, init);
request.headers.set('x-custom-header', '42');
return fetch(request);
}

const HomeScreen: React.FC = () => {
const [initialized, setInitialized] = useState(false);
const [loading, setLoading] = useState(false);
Expand Down Expand Up @@ -383,6 +393,7 @@ const HomeScreen: React.FC = () => {
: undefined,
isSSOEnabled,
preAuthenticatedURLEnabled,
fetch: myfetch,
})
.then(() => {
postConfigure();
Expand Down
46 changes: 30 additions & 16 deletions example/reactweb/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ function ShowError(props: { error: unknown }) {
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

async function myfetch(
input: URL | RequestInfo,
init?: RequestInit
): Promise<Response> {
const request = new Request(input, init);
request.headers.set("x-custom-header", "42");
return fetch(request);
}

function Root() {
const initialClientID = readClientID();
const initialEndpoint = readEndpoint();
Expand All @@ -94,7 +103,8 @@ function Root() {
const [endpoint, setEndpoint] = useState(initialEndpoint);
const [isSSOEnabled, setIsSSOEnabled] = useState(initialIsSSOEnabled);
const [page, setPage] = useState<string>();
const [authenticationFlowGroup, setAuthenticationflowGroup] = useState<string>("");
const [authenticationFlowGroup, setAuthenticationflowGroup] =
useState<string>("");

const [error, setError] = useState<unknown>(null);
const [userInfo, setUserInfo] = useState<UserInfo | null>(null);
Expand Down Expand Up @@ -122,6 +132,7 @@ function Root() {
clientID,
sessionType,
isSSOEnabled,
fetch: myfetch,
})
.then(
() => {
Expand Down Expand Up @@ -225,21 +236,24 @@ function Root() {
);
}, []);

const onClickSignIn = useCallback((e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
e.stopPropagation();
authgear
.startAuthentication({
redirectURI: makeRedirectURI(),
state: "authenticate",
page,
authenticationFlowGroup,
})
.then(
() => {},
(err) => setError(err)
);
}, [page, authenticationFlowGroup]);
const onClickSignIn = useCallback(
(e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
e.stopPropagation();
authgear
.startAuthentication({
redirectURI: makeRedirectURI(),
state: "authenticate",
page,
authenticationFlowGroup,
})
.then(
() => {},
(err) => setError(err)
);
},
[page, authenticationFlowGroup]
);

const onClickSignInAnonymously = useCallback(
(e: React.MouseEvent<HTMLElement>) => {
Expand Down
35 changes: 21 additions & 14 deletions packages/authgear-capacitor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,16 @@ export interface ConfigureOptions {
* The UIImplementation.
*/
uiImplementation?: UIImplementation;
}

/**
* @internal
*/
export class _CapacitorAPIClient extends _BaseAPIClient {
_fetchFunction = window.fetch.bind(window);
_requestClass = Request;
/*
* Override the fetch() function the SDK uses to access the endpoint.
* If this is not specified, the global fetch() function is used.
* Note that the fetch() function IS NOT used in the UIImplementation,
* it is only used to access endpoints like the Token endpoint.
* For example, you want to provide a custom fetch() function to include additional headers
* in all requests that are sent to your self-hosted deployment.
*/
fetch?: typeof window.fetch;
}

async function getXDeviceInfo(): Promise<string> {
Expand All @@ -151,7 +153,7 @@ export class CapacitorContainer {
/**
* @internal
*/
baseContainer: _BaseContainer<_CapacitorAPIClient>;
baseContainer: _BaseContainer<_BaseAPIClient>;

/**
* @internal
Expand Down Expand Up @@ -270,13 +272,14 @@ export class CapacitorContainer {
},
});
this.dpopProvider = dpopProvider;
const apiClient = new _CapacitorAPIClient(dpopProvider);

this.baseContainer = new _BaseContainer<_CapacitorAPIClient>(
o,
apiClient,
this
);
const apiClient = new _BaseAPIClient({
fetch: window.fetch.bind(window),
Request: Request,
dpopProvider,
});

this.baseContainer = new _BaseContainer<_BaseAPIClient>(o, apiClient, this);
this.baseContainer.apiClient._delegate = this;

this.storage = new PersistentContainerStorage();
Expand Down Expand Up @@ -373,7 +376,11 @@ export class CapacitorContainer {
const refreshToken = await this.tokenStorage.getRefreshToken(this.name);

this.clientID = options.clientID;

this.baseContainer.apiClient._fetch =
options.fetch ?? window.fetch.bind(window);
this.baseContainer.apiClient.endpoint = options.endpoint;

this.baseContainer.refreshToken = refreshToken ?? undefined;
this.baseContainer.accessToken = undefined;

Expand Down
35 changes: 15 additions & 20 deletions packages/authgear-core/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function _removeTrailingSlash(s: string): string {
/**
* @internal
*/
export abstract class _BaseAPIClient {
export class _BaseAPIClient {
private dpopProvider: DPoPProvider | null;
userAgent?: string;

Expand All @@ -47,15 +47,21 @@ export abstract class _BaseAPIClient {
}

// eslint-disable-next-line no-undef
abstract _fetchFunction?: typeof fetch;

_fetch: typeof fetch;
// eslint-disable-next-line no-undef
abstract _requestClass?: typeof Request;
_Request: typeof Request;

_config?: _OIDCConfiguration;

constructor(dpopProvider: DPoPProvider | null) {
this.dpopProvider = dpopProvider;
constructor(options: {
// eslint-disable-next-line no-undef
fetch: typeof fetch;
Request: typeof Request;
dpopProvider: DPoPProvider | null;
}) {
this._fetch = options.fetch;
this._Request = options.Request;
this.dpopProvider = options.dpopProvider;
}

protected async _prepareHeaders(): Promise<Record<string, string>> {
Expand All @@ -71,10 +77,6 @@ export abstract class _BaseAPIClient {
}

async _doFetch(request: Request): Promise<Response> {
if (!this._fetchFunction) {
throw new AuthgearError("missing fetchFunction in api client");
}

if (this.dpopProvider != null) {
const dpopJWT = await this.dpopProvider.generateDPoPProof({
htm: request.method,
Expand All @@ -85,25 +87,18 @@ export abstract class _BaseAPIClient {
}
}

return this._fetchFunction(request);
return this._fetch(request);
}

async _fetchWithoutRefresh(
url: string,
init?: RequestInit
): Promise<Response> {
if (!this._requestClass) {
throw new AuthgearError("missing requestClass in api client");
}
const request = new this._requestClass(url, init);
const request = new this._Request(url, init);
return this._doFetch(request);
}

async fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
if (this._requestClass == null) {
throw new AuthgearError("missing requestClass in api client");
}

if (this._delegate == null) {
throw new AuthgearError("missing delegate in api client");
}
Expand All @@ -113,7 +108,7 @@ export abstract class _BaseAPIClient {
await this._delegate.refreshAccessToken();
}

const request = new this._requestClass(input, init);
const request = new this._Request(input, init);

const headers = await this._prepareHeaders();
for (const key of Object.keys(headers)) {
Expand Down
31 changes: 17 additions & 14 deletions packages/authgear-react-native/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,16 @@ export interface ConfigureOptions {
* The implementation of UIImplementation.
*/
uiImplementation?: UIImplementation;
}

/**
* @internal
*/
export class _ReactNativeAPIClient extends _BaseAPIClient {
_fetchFunction = fetch;
_requestClass = Request;
/*
* Override the fetch() function the SDK uses to access the endpoint.
* If this is not specified, the global fetch() function is used.
* Note that the fetch() function IS NOT used in the UIImplementation,
* it is only used to access endpoints like the Token endpoint.
* For example, you want to provide a custom fetch() function to include additional headers
* in all requests that are sent to your self-hosted deployment.
*/
fetch?: typeof fetch;
}

async function getXDeviceInfo(): Promise<string> {
Expand All @@ -143,7 +145,7 @@ export class ReactNativeContainer {
/**
* @internal
*/
baseContainer: _BaseContainer<_ReactNativeAPIClient>;
baseContainer: _BaseContainer<_BaseAPIClient>;

/**
* @internal
Expand Down Expand Up @@ -280,13 +282,13 @@ export class ReactNativeContainer {
});

this.dpopProvider = dpopProvider;
const apiClient = new _ReactNativeAPIClient(dpopProvider);
const apiClient = new _BaseAPIClient({
fetch: fetch,
Request: Request,
dpopProvider: dpopProvider,
});

this.baseContainer = new _BaseContainer<_ReactNativeAPIClient>(
o,
apiClient,
this
);
this.baseContainer = new _BaseContainer<_BaseAPIClient>(o, apiClient, this);
this.baseContainer.apiClient._delegate = this;

this.storage = new PersistentContainerStorage();
Expand Down Expand Up @@ -395,6 +397,7 @@ export class ReactNativeContainer {
const refreshToken = await this.tokenStorage.getRefreshToken(this.name);

this.clientID = options.clientID;
this.baseContainer.apiClient._fetch = options.fetch ?? fetch;
this.baseContainer.apiClient.endpoint = options.endpoint;
this.baseContainer.refreshToken = refreshToken ?? undefined;
this.baseContainer.accessToken = undefined;
Expand Down
19 changes: 0 additions & 19 deletions packages/authgear-web/src/client.ts

This file was deleted.

Loading