import { H2, H4 } from '@expo/html-elements'; import * as AuthSession from 'expo-auth-session'; import { useAuthRequest } from 'expo-auth-session'; import * as FacebookAuthSession from 'expo-auth-session/providers/facebook'; import * as GoogleAuthSession from 'expo-auth-session/providers/google'; import Constants, { ExecutionEnvironment } from 'expo-constants'; import { maybeCompleteAuthSession } from 'expo-web-browser'; import React from 'react'; import { Platform, ScrollView, View } from 'react-native'; import { AuthSection } from './AuthResult'; import { getGUID } from '../../api/guid'; import TitledPicker from '../../components/TitledPicker'; import TitledSwitch from '../../components/TitledSwitch'; maybeCompleteAuthSession(); const isInClient = Constants.executionEnvironment === ExecutionEnvironment.StoreClient; const languages = [ { key: 'en', value: 'English' }, { key: 'pl', value: 'Polish' }, { key: 'nl', value: 'Dutch' }, { key: 'fi', value: 'Finnish' }, ]; const PROJECT_NAME_FOR_PROXY = '@community/native-component-list'; export default function AuthSessionScreen() { const [usePKCE, setPKCE] = React.useState(true); const [prompt, setSwitch] = React.useState(undefined); const [language, setLanguage] = React.useState(languages[0].key); return (

Settings

setSwitch(value ? AuthSession.Prompt.SelectAccount : undefined)} />

ID: {PROJECT_NAME_FOR_PROXY}

Services

); } AuthSessionScreen.navigationOptions = { title: 'AuthSession', }; function AuthSessionProviders(props: { usePKCE: boolean; prompt?: AuthSession.Prompt; language: string; }) { const { usePKCE, prompt, language } = props; const redirectUri = AuthSession.makeRedirectUri({ path: 'redirect', preferLocalhost: Platform.select({ android: false, default: true }), }); const options = { usePKCE, prompt, redirectUri, language, }; const providers = [ Google, GoogleFirebase, Facebook, Imgur, Spotify, Strava, Twitch, Dropbox, Reddit, Github, Coinbase, Uber, Slack, FitBit, Okta, Identity, // Azure, ]; return ( {providers.map((Provider, index) => ( ))} ); } function Google({ prompt, language, usePKCE }: any) { const [request, result, promptAsync] = GoogleAuthSession.useAuthRequest( { language, expoClientId: '629683148649-qevd4mfvh06q14i4nl453r62sgd1p85d.apps.googleusercontent.com', clientId: `${getGUID()}.apps.googleusercontent.com`, selectAccount: !!prompt, usePKCE, }, { path: 'redirect', preferLocalhost: true, } ); React.useEffect(() => { if (request && result?.type === 'success') { console.log('Result: ', result.authentication); } }, [result]); return ; } function GoogleFirebase({ prompt, language, usePKCE }: any) { const [request, result, promptAsync] = GoogleAuthSession.useIdTokenAuthRequest( { language, expoClientId: '629683148649-qevd4mfvh06q14i4nl453r62sgd1p85d.apps.googleusercontent.com', clientId: `${getGUID()}.apps.googleusercontent.com`, selectAccount: !!prompt, usePKCE, }, { path: 'redirect', preferLocalhost: true, } ); React.useEffect(() => { if (request && result?.type === 'success') { console.log('Result:', result.params.id_token); } }, [result]); return ( ); } // Couldn't get this working. API is really confusing. // function Azure({ useProxy, prompt, usePKCE }: any) { // const redirectUri = AuthSession.makeRedirectUri({ // path: 'redirect', // preferLocalhost: true, // useProxy, // native: Platform.select({ // ios: 'msauth.dev.expo.Payments://auth', // android: 'msauth://dev.expo.payments/sZs4aocytGUGvP1%2BgFAavaPMPN0%3D', // }), // }); // // 'https://login.microsoftonline.com/your-tenant-id/v2.0', // const discovery = AuthSession.useAutoDiscovery( // 'https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0' // ); // const [request, result, promptAsync] = useAuthRequest( // // config // { // clientId: '96891596-721b-4ae1-8e67-674809373165', // redirectUri, // prompt, // extraParams: { // domain_hint: 'live.com', // }, // // redirectUri: 'msauth.{bundleId}://auth', // scopes: ['openid', 'profile', 'email', 'offline_access'], // usePKCE, // }, // // discovery // discovery // ); // return ( // // ); // } function Okta({ redirectUri, usePKCE }: any) { const discovery = AuthSession.useAutoDiscovery('https://dev-720924.okta.com/oauth2/default'); const [request, result, promptAsync] = useAuthRequest( { clientId: '0oa4su9fhp4F2F4Eg4x6', redirectUri, scopes: ['openid', 'profile'], usePKCE, }, discovery ); return ; } // Reddit only allows one redirect uri per client Id // We'll only support bare, and proxy in this example // If the redirect is invalid with http instead of https on web, then the provider // will let you authenticate but it will redirect with no data and the page will appear broken. function Reddit({ redirectUri, prompt, usePKCE }: any) { let clientId: string; if (isInClient) { clientId = 'CPc_adCUQGt9TA'; } else { if (Platform.OS === 'web') { // web apps with uri scheme `https://localhost:19006` clientId = '9k_oYNO97ly-5w'; } else { // Native bare apps with uri scheme `bareexpo` clientId = '2OFsAA7h63LQJQ'; } } const [request, result, promptAsync] = useAuthRequest( { clientId, clientSecret: '', redirectUri, prompt, scopes: ['identity'], usePKCE, }, { authorizationEndpoint: 'https://www.reddit.com/api/v1/authorize.compact', tokenEndpoint: 'https://www.reddit.com/api/v1/access_token', } ); return ; } // Imgur Docs https://api.imgur.com/oauth2 // Create app https://api.imgur.com/oauth2/addclient function Imgur({ redirectUri, prompt, usePKCE }: any) { let clientId: string; if (isInClient) { // Normalize the host to `localhost` for other testers // Expects: exp://127.0.0.1:19000/--/redirect clientId = '7ab2f3cc75427a0'; } else { if (Platform.OS === 'web') { // web apps with uri scheme `https://localhost:19006` clientId = '181b22d17a3743e'; } else { // Native bare apps with uri scheme `bareexpo` clientId = 'd839d91135a16cc'; } } const [request, result, promptAsync] = useAuthRequest( { clientId, responseType: AuthSession.ResponseType.Token, redirectUri, scopes: [], usePKCE, prompt, }, // discovery { authorizationEndpoint: 'https://api.imgur.com/oauth2/authorize', tokenEndpoint: 'https://api.imgur.com/oauth2/token', } ); return ( promptAsync({ windowFeatures: { width: 500, height: 750 }, }) } /> ); } // TODO: Add button to test using an invalid redirect URI. This is a good example of AuthError. // Works for all platforms function Github({ redirectUri, prompt, usePKCE }: any) { let clientId: string; if (isInClient) { clientId = '7eb5d82d8f160a434564'; } else { if (Platform.OS === 'web') { // web apps clientId = 'fd9b07204f9d325e8f0e'; } else { // Native bare apps with uri scheme `bareexpo` clientId = '498f1fae3ae16f066f34'; } } const [request, result, promptAsync] = useAuthRequest( { clientId, redirectUri, scopes: ['identity'], usePKCE, prompt, }, // discovery { authorizationEndpoint: 'https://github.com/login/oauth/authorize', tokenEndpoint: 'https://github.com/login/oauth/access_token', revocationEndpoint: 'https://github.com/settings/connections/applications/d529db5d7d81c2d50adf', } ); return ( promptAsync({ windowFeatures: { width: 500, height: 750 }, }) } /> ); } // I couldn't get access to any scopes // This never returns to the app after authenticating function Uber({ redirectUri, prompt, usePKCE }: any) { // https://developer.uber.com/docs/riders/guides/authentication/introduction const [request, result, promptAsync] = useAuthRequest( { clientId: 'kTpT4xf8afVxifoWjx5Nhn-IFamZKp2x', redirectUri, scopes: [], usePKCE, prompt, // Enable to test invalid_scope error // scopes: ['invalid'], }, // discovery { authorizationEndpoint: 'https://login.uber.com/oauth/v2/authorize', tokenEndpoint: 'https://login.uber.com/oauth/v2/token', revocationEndpoint: 'https://login.uber.com/oauth/v2/revoke', } ); return ; } // https://dev.fitbit.com/apps/new // Easy to setup // Only allows one redirect URI per app (clientId) // Refresh doesn't seem to return a new access token :[ function FitBit({ redirectUri, prompt, usePKCE }: any) { let clientId: string; if (isInClient) { // Client without proxy clientId = '22BNXX'; } else { if (Platform.OS === 'web') { // web apps with uri scheme `https://localhost:19006` clientId = '22BNXQ'; } else { // Native bare apps with uri scheme `bareexpo` clientId = '22BGYS'; } } const [request, result, promptAsync] = useAuthRequest( { clientId, redirectUri, scopes: ['activity', 'sleep'], prompt, usePKCE, }, // discovery { authorizationEndpoint: 'https://www.fitbit.com/oauth2/authorize', tokenEndpoint: 'https://api.fitbit.com/oauth2/token', revocationEndpoint: 'https://api.fitbit.com/oauth2/revoke', } ); return ; } function Facebook({ usePKCE, language }: any) { const [request, result, promptAsync] = FacebookAuthSession.useAuthRequest( { clientId: '145668956753819', usePKCE, language, scopes: ['user_likes'], }, { path: 'redirect', preferLocalhost: true, } ); // Add fetch user example return ( ); } function Slack({ redirectUri, prompt, usePKCE }: any) { // https://api.slack.com/apps // After you created an app, navigate to [Features > OAuth & Permissions] // - Add a redirect URI Under [Redirect URLs] // - Under [Scopes] add the scopes you want to request from the user // Next go to [App Credentials] to get your client ID and client secret // No refresh token or expiration is returned, assume the token lasts forever. const [request, result, promptAsync] = useAuthRequest( // config { clientId: '58692702102.1023025401076', redirectUri, scopes: ['emoji:read'], prompt, usePKCE, }, // discovery { authorizationEndpoint: 'https://slack.com/oauth/authorize', tokenEndpoint: 'https://slack.com/api/oauth.access', } ); return ; } // Works on all platforms function Spotify({ redirectUri, prompt, usePKCE }: any) { const [request, result, promptAsync] = useAuthRequest( { clientId: 'a946eadd241244fd88d0a4f3d7dea22f', redirectUri, scopes: ['user-read-email', 'playlist-modify-public', 'user-read-private'], usePKCE, extraParams: { show_dialog: 'false', }, prompt, }, // discovery { authorizationEndpoint: 'https://accounts.spotify.com/authorize', tokenEndpoint: 'https://accounts.spotify.com/api/token', } ); return ( ); } function Strava({ redirectUri, prompt, usePKCE }: any) { const discovery = { authorizationEndpoint: 'https://www.strava.com/oauth/mobile/authorize', tokenEndpoint: 'https://www.strava.com/oauth/token', }; const [request, result, promptAsync] = useAuthRequest( { clientId: '51935', redirectUri, scopes: ['activity:read_all'], usePKCE, prompt, }, discovery ); React.useEffect(() => { if (request && result?.type === 'success' && result.params.code) { AuthSession.exchangeCodeAsync( { clientId: request?.clientId, redirectUri, code: result.params.code, extraParams: { // You must use the extraParams variation of clientSecret. client_secret: `...`, }, }, discovery ).then((result) => { console.log('RES: ', result); }); } }, [result]); return ; } // Works on all platforms function Identity({ redirectUri, prompt }: any) { const discovery = AuthSession.useAutoDiscovery('https://demo.identityserver.io'); const [request, result, promptAsync] = useAuthRequest( { clientId: 'native.code', redirectUri, prompt, scopes: ['openid', 'profile', 'email', 'offline_access'], }, discovery ); return ( ); } // Doesn't work with proxy function Coinbase({ redirectUri, prompt, usePKCE }: any) { const [request, result, promptAsync] = useAuthRequest( { clientId: '13b2bc8d9114b1cb6d0132cf60c162bc9c2d5ec29c2599003556edf81cc5db4e', redirectUri, prompt, usePKCE, scopes: ['wallet:accounts:read'], }, // discovery { authorizationEndpoint: 'https://www.coinbase.com/oauth/authorize', tokenEndpoint: 'https://api.coinbase.com/oauth/token', revocationEndpoint: 'https://api.coinbase.com/oauth/revoke', } ); return ( ); } function Dropbox({ redirectUri, prompt, usePKCE }: any) { const [request, result, promptAsync] = useAuthRequest( { clientId: 'pjvyj0c5kxxrsfs', redirectUri, prompt, usePKCE, scopes: [], responseType: AuthSession.ResponseType.Token, }, // discovery { authorizationEndpoint: 'https://www.dropbox.com/oauth2/authorize', tokenEndpoint: 'https://www.dropbox.com/oauth2/token', } ); return ( ); } function Twitch({ redirectUri, prompt, usePKCE }: any) { const [request, result, promptAsync] = useAuthRequest( { clientId: 'r7jomrc4hiz5wm1wgdzmwr1ccb454h', redirectUri, prompt, scopes: ['openid', 'user_read', 'analytics:read:games'], usePKCE, }, { authorizationEndpoint: 'https://id.twitch.tv/oauth2/authorize', tokenEndpoint: 'https://id.twitch.tv/oauth2/token', revocationEndpoint: 'https://id.twitch.tv/oauth2/revoke', } ); return ; }