expo 项目, 实现 okta 登录(Typescript)
Button, Text 组件引用于 React Native Elements
expo 使用 okta 的官方文档的使用说明, docs.expo.dev/guides/auth...
官方 code 示例:
javascript
import * as React from 'react';
import * as WebBrowser from 'expo-web-browser';
import { makeRedirectUri, useAuthRequest, useAutoDiscovery } from 'expo-auth-session';
import { Button, Platform } from 'react-native';
WebBrowser.maybeCompleteAuthSession();
export default function App() {
// Endpoint
const discovery = useAutoDiscovery('https://<OKTA_DOMAIN>.com/oauth2/default');
// Request
const [request, response, promptAsync] = useAuthRequest(
{
clientId: 'CLIENT_ID',
scopes: ['openid', 'profile'],
redirectUri: makeRedirectUri({
native: 'com.okta.<OKTA_DOMAIN>:/callback',
}),
},
discovery
);
React.useEffect(() => {
if (response?.type === 'success') {
const { code } = response.params;
}
}, [response]);
return (
<Button
disabled={!request}
title="Login"
onPress={() => {
promptAsync();
}}
/>
);
}
这里的针对自己的项目需要做些调整与解释:
clientId
,scopes
,redirectUri
,discovery
- 返回
code
之后, 怎么使用? 怎么拿到accessToken
- 设置
.env
存放敏感配置
config
EXPO_PUBLIC_OKTA_CLIENT_ID=0oaxxxxxxxxxxxxxxxxx
EXPO_PUBLIC_OKTA_ISSUER=https://<my_company_name>.okta.com/oauth2/ausxxxxxxxxxxxxxxxxx
EXPO_PUBLIC_OKTA_CALLBACK=<my_company_name>-data://callback
注意: CLIENT_ID
一般是 0oaxxxxxxxxxxxxxxxxx
开头, 20 位
- 直接使用
注意:
redirectUri
是直接使用process.env.EXPO_PUBLIC_OKTA_CALLBACK
并没有调用makeRedirectUri
scopes
可能根据个人需要调整const discovery = useAutoDiscovery(oktaConfig.issuerUrl);
会在useAuthRequest
与exchangeCodeAsync
中用到.discovery
的类型是DiscoveryDocument
codes:
js
import { Button, Text } from "@rneui/themed";
import {
DiscoveryDocument,
TokenResponse,
TokenResponseConfig,
exchangeCodeAsync,
useAuthRequest,
useAutoDiscovery,
} from "expo-auth-session";
import * as WebBrowser from "expo-web-browser";
import * as React from "react";
import { ScrollView, StyleSheet, View } from "react-native";
WebBrowser.maybeCompleteAuthSession();
// okta configuration
const oktaConfig = {
clientId: process.env.EXPO_PUBLIC_OKTA_CLIENT_ID as string,
scopes: ["openid", "profile", "email", "groups"],
issuerUrl: process.env.EXPO_PUBLIC_OKTA_ISSUER as string,
callbackUrl: process.env.EXPO_PUBLIC_OKTA_CALLBACK as string,
};
export default function App() {
// Endpoint
const discovery = useAutoDiscovery(oktaConfig.issuerUrl);
// Request
const [request, response, promptAsync] = useAuthRequest(
{
clientId: oktaConfig.clientId,
scopes: oktaConfig.scopes,
redirectUri: oktaConfig.callbackUrl,
},
discovery
);
React.useEffect(() => {
if (response?.type === "success") {
const { code } = response.params;
if (request && code) {
// function for retrieving the access token and refresh token from our code
const getToken = async () => {
const codeRes: TokenResponse = await exchangeCodeAsync(
{
code,
redirectUri: oktaConfig.callbackUrl,
extraParams: request.codeVerifier
? { code_verifier: request.codeVerifier }
: undefined,
clientId: oktaConfig.clientId,
},
discovery as DiscoveryDocument
);
// get the config from our response to cache for later refresh
const tokenConfig: TokenResponseConfig = codeRes?.getRequestConfig();
// get the access token to use
const jwtToken = tokenConfig.accessToken;
// caching the token for later
console.log("jwtToken: ", jwtToken);
// decoding the token for getting user profile information
};
getToken();
}
}
}, [response]);
return (
<View style={styles.container}>
<ScrollView>
{response && <Text>{JSON.stringify(response, null, 2)}</Text>}
</ScrollView>
<Button
title="Log in"
loading={false}
loadingProps={{ size: "small", color: "white" }}
buttonStyle={{
backgroundColor: "rgba(111, 202, 186, 1)",
borderRadius: 5,
}}
titleStyle={{ fontWeight: "bold", fontSize: 23 }}
containerStyle={{
marginHorizontal: 50,
height: 50,
width: 200,
marginVertical: 10,
}}
onPress={() => {
promptAsync();
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
margin: 10,
marginTop: 20,
},
});
参考:
希望对 expo 开发, 对接 okta 的开发者有帮助, saved your time.