proposal-system/mobile/src/lib/api/auth.ts

79 lines
2.1 KiB
TypeScript
Raw Normal View History

import { authorize, refresh, revoke } from 'react-native-app-auth';
import Config from '../../config';
import apiClient from './client';
import {
tokenStorage,
userStorage,
StoredTokens,
StoredUser,
} from '../storage';
const cognitoConfig = {
clientId: Config.COGNITO_CLIENT_ID,
redirectUrl: Config.COGNITO_REDIRECT_URI,
scopes: Config.COGNITO_SCOPES,
serviceConfiguration: {
authorizationEndpoint: `https://${Config.COGNITO_DOMAIN}/oauth2/authorize`,
tokenEndpoint: `https://${Config.COGNITO_DOMAIN}/oauth2/token`,
revocationEndpoint: `https://${Config.COGNITO_DOMAIN}/oauth2/revoke`,
},
usePKCE: true,
iosPrefersEphemeralSession: false,
};
export const authApi = {
login: async (): Promise<StoredUser> => {
const result = await authorize(cognitoConfig);
const tokens: StoredTokens = {
accessToken: result.accessToken,
idToken: result.idToken,
refreshToken: result.refreshToken,
expiresAt: result.accessTokenExpirationDate,
};
await tokenStorage.save(tokens);
const profile = await authApi.getMe();
await userStorage.save(profile);
return profile;
},
refreshTokens: async (): Promise<void> => {
const stored = await tokenStorage.get();
if (!stored?.refreshToken) throw new Error('No refresh token');
const result = await refresh(cognitoConfig, {
refreshToken: stored.refreshToken,
});
await tokenStorage.save({
accessToken: result.accessToken,
idToken: result.idToken || stored.idToken,
refreshToken: result.refreshToken || stored.refreshToken,
expiresAt: result.accessTokenExpirationDate,
});
},
logout: async (): Promise<void> => {
const stored = await tokenStorage.get();
if (stored?.accessToken) {
try {
await revoke(cognitoConfig, {
tokenToRevoke: stored.accessToken,
includeBasicAuth: false,
sendClientId: true,
});
} catch {
// Best-effort revocation
}
}
await tokenStorage.clear();
await userStorage.clear();
},
getMe: async (): Promise<StoredUser> => {
const res = await apiClient.get('/users/me');
return res.data;
},
};