import { H2 } from '@expo/html-elements'; import * as AuthSession from 'expo-auth-session'; import { useAuthRequest } from 'expo-auth-session'; import Constants from 'expo-constants'; import { maybeCompleteAuthSession } from 'expo-web-browser'; import React from 'react'; import { Platform, ScrollView, View } from 'react-native'; import { getGUID } from '../../api/guid'; import TitledSwitch from '../../components/TitledSwitch'; import { AuthSection } from './AuthResult'; import LegacyAuthSession from './LegacyAuthSession'; maybeCompleteAuthSession(); const isInClient = Platform.OS !== 'web' && Constants.appOwnership === 'expo'; export default function AuthSessionScreen() { const [useProxy, setProxy] = React.useState(false); const [usePKCE, setPKCE] = React.useState(true); const [prompt, setSwitch] = React.useState(undefined); return (

Settings

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

Services

Legacy

); } AuthSessionScreen.navigationOptions = { title: 'AuthSession', }; function AuthSessionProviders(props: { useProxy: boolean; usePKCE: boolean; prompt?: AuthSession.Prompt; }) { const { useProxy, usePKCE, prompt } = props; const redirectUri = AuthSession.makeRedirectUri({ native: 'bareexpo://redirect', path: 'redirect', preferLocalhost: true, useProxy, }); const options = { useProxy, usePKCE, prompt, redirectUri, }; const providers = [ Facebook, Spotify, Twitch, Dropbox, Google, Reddit, Github, Coinbase, Uber, Slack, FitBit, Okta, Identity, // Azure, ]; return ( {providers.map((Provider, index) => ( ))} ); } function Google({ useProxy, prompt, usePKCE }: any) { const redirectUri = AuthSession.makeRedirectUri({ path: 'redirect', preferLocalhost: true, useProxy, native: `com.googleusercontent.apps.${getGUID()}:/oauthredirect`, }); const discovery = AuthSession.useAutoDiscovery('https://accounts.google.com'); const [request, result, promptAsync] = useAuthRequest( { clientId: useProxy ? '29635966244-bc5tjrdacdaktqorhinsbtda80tchl7n.apps.googleusercontent.com' : getGUID(), redirectUri, prompt, scopes: ['profile', 'email', 'openid'], usePKCE, }, discovery ); return ( promptAsync({ useProxy, windowFeatures: { width: 515, height: 680 } })} useProxy={useProxy} /> ); } // 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, useProxy }: 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, useProxy }: any) { let clientId: string; if (isInClient) { if (useProxy) { // Using the proxy in the client. // This expects the URI to be 'https://auth.expo.io/@community/native-component-list' // so you'll need to be signed into community or be using the public demo clientId = 'IlgcZIpcXF1eKw'; } else { // // Normalize the host to `localhost` for other testers 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 ( ); } // 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, useProxy }: any) { let clientId: string; if (isInClient) { if (useProxy) { // Using the proxy in the client. clientId = '2e4298cafc7bc93ceab8'; } else { 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({ useProxy, windowFeatures: { width: 500, height: 750 } })} useProxy={useProxy} /> ); } // I couldn't get access to any scopes // This never returns to the app after authenticating function Uber({ redirectUri, prompt, usePKCE, useProxy }: 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, useProxy }: any) { let clientId: string; if (isInClient) { if (useProxy) { // Using the proxy in the client. clientId = '22BNXR'; } else { // 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, prompt, useProxy }: any) { const redirectUri = AuthSession.makeRedirectUri({ path: 'redirect', preferLocalhost: true, useProxy, native: `fb145668956753819://authorize`, }); const [request, result, promptAsync] = useAuthRequest( { clientId: '145668956753819', redirectUri, scopes: ['public_profile', 'user_likes'], usePKCE, prompt, extraParams: { display: 'popup', // Rerequest decliened permissions, to test this, // add "email" to the scopes and try again (be sure not to allow email permission). auth_type: 'rerequest', }, }, { authorizationEndpoint: 'https://www.facebook.com/v6.0/dialog/oauth', tokenEndpoint: 'https://graph.facebook.com/v6.0/oauth/access_token', } ); return ( promptAsync({ useProxy, windowFeatures: { width: 700, height: 600 } })} useProxy={useProxy} /> ); } function Slack({ redirectUri, prompt, usePKCE, useProxy }: 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, useProxy }: 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 ( ); } // Works on all platforms function Identity({ redirectUri, prompt, useProxy }: 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, useProxy }: 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, useProxy }: 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, useProxy }: 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 ( ); }