UNPKG

5.14 kBJavaScriptView Raw
1import { CodedError, UnavailabilityError } from '@unimodules/core';
2import invariant from 'invariant';
3import ExpoAppAuth from './ExpoAppAuth';
4function isValidServiceConfiguration(config) {
5 return !!(config &&
6 typeof config.authorizationEndpoint === 'string' &&
7 typeof config.tokenEndpoint === 'string');
8}
9function assertValidClientId(clientId) {
10 if (typeof clientId !== 'string' || !clientId.length) {
11 throw new CodedError('ERR_APP_AUTH_INVALID_CONFIG', '`clientId` must be a string with more than 0 characters');
12 }
13}
14function assertValidProps({ issuer, redirectUrl, clientId, serviceConfiguration, }) {
15 if (typeof issuer !== 'string' && !isValidServiceConfiguration(serviceConfiguration)) {
16 throw new CodedError('ERR_APP_AUTH_INVALID_CONFIG', 'You must provide either an `issuer` or both `authorizationEndpoint` and `tokenEndpoint`');
17 }
18 if (typeof redirectUrl !== 'string') {
19 throw new CodedError('ERR_APP_AUTH_INVALID_CONFIG', '`redirectUrl` must be a string');
20 }
21 assertValidClientId(clientId);
22}
23async function _executeAsync(props) {
24 if (!props.redirectUrl) {
25 props.redirectUrl = getDefaultOAuthRedirect();
26 }
27 assertValidProps(props);
28 return await ExpoAppAuth.executeAsync(props);
29}
30export function getDefaultOAuthRedirect() {
31 return `${ExpoAppAuth.OAuthRedirect}:/oauthredirect`;
32}
33export async function authAsync(props) {
34 if (!ExpoAppAuth.executeAsync) {
35 throw new UnavailabilityError('expo-app-auth', 'authAsync');
36 }
37 return await _executeAsync(props);
38}
39export async function refreshAsync(props, refreshToken) {
40 if (!ExpoAppAuth.executeAsync) {
41 throw new UnavailabilityError('expo-app-auth', 'refreshAsync');
42 }
43 if (!refreshToken) {
44 throw new CodedError('ERR_APP_AUTH_TOKEN', 'Cannot refresh with null `refreshToken`');
45 }
46 return await _executeAsync({
47 isRefresh: true,
48 refreshToken,
49 ...props,
50 });
51}
52/* JS Method */
53export async function revokeAsync({ clientId, issuer, serviceConfiguration }, { token, isClientIdProvided = false }) {
54 if (!token) {
55 throw new CodedError('ERR_APP_AUTH_TOKEN', 'Cannot revoke a null `token`');
56 }
57 assertValidClientId(clientId);
58 let revocationEndpoint;
59 if (serviceConfiguration && serviceConfiguration.revocationEndpoint) {
60 revocationEndpoint = serviceConfiguration.revocationEndpoint;
61 }
62 else {
63 // For Open IDC providers only.
64 const response = await fetch(`${issuer}/.well-known/openid-configuration`);
65 const openidConfig = await response.json();
66 invariant(openidConfig.revocation_endpoint, 'The OpenID config does not specify a revocation endpoint');
67 revocationEndpoint = openidConfig.revocation_endpoint;
68 }
69 const encodedClientID = encodeURIComponent(clientId);
70 const encodedToken = encodeURIComponent(token);
71 const body = `token=${encodedToken}${isClientIdProvided ? `&client_id=${encodedClientID}` : ''}`;
72 const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
73 try {
74 // https://tools.ietf.org/html/rfc7009#section-2.2
75 const results = await fetch(revocationEndpoint, {
76 method: 'POST',
77 headers,
78 body,
79 });
80 return results;
81 }
82 catch (error) {
83 throw new CodedError('ERR_APP_AUTH_REVOKE_FAILED', error.message);
84 }
85}
86// NOTE: This function is unused; delete it if we don't need it
87// eslint-disable-next-line @typescript-eslint/no-unused-vars
88async function parseAuthRevocationResults(results) {
89 const data = await results.json();
90 const token = results.headers['update-client-auth'];
91 // the token has been revoked successfully or the client submitted an invalid token.
92 if (results.ok) {
93 // successful op
94 return { type: 'success', status: results.status, data, token };
95 }
96 else if (results.status === 503 && results.headers['retry-after']) {
97 // Failed op
98 const retryAfterValue = results.headers['retry-after'];
99 let retryAfter;
100 if (retryAfterValue) {
101 retryAfter = parseRetryTime(retryAfterValue);
102 }
103 // the client must assume the token still exists and may retry after a reasonable delay.
104 return { type: 'failed', status: results.status, data, token, retryAfter };
105 }
106 else {
107 // Error
108 return { type: 'error', status: results.status, data, token };
109 }
110}
111function parseRetryTime(value) {
112 // In accordance with RFC2616, Section 14.37. Timout may be of format seconds or future date time value
113 if (/^\d+$/.test(value)) {
114 return parseInt(value, 10) * 1000;
115 }
116 const retry = Date.parse(value);
117 if (isNaN(retry)) {
118 throw new CodedError('ERR_APP_AUTH_FETCH_RETRY_TIME', 'Cannot parse the Retry-After header value returned by the server: ' + value);
119 }
120 const now = Date.now();
121 const parsedDate = new Date(retry);
122 return parsedDate.getTime() - now;
123}
124export const { OAuthRedirect, URLSchemes } = ExpoAppAuth;
125//# sourceMappingURL=AppAuth.js.map
\No newline at end of file