英文:
Fusion Auth is not redirecting to the Expo App oauth callback route after authorization
问题
I am writing an app in Expo. I am using Fusion Auth as an auth server, hosted locally.
I want to use the OAuth authorization flow with PKCE. The app is sending a request to /authorize, then I am getting the code. The auth server should redirect me to the auth callback route. However, Fusion Auth is not redirecting me to the auth callback route but closes the browser modal and keeps the login page active.
I am writing code with Expo Auth Session.
This is my application's Fusion Auth configuration:
And this is my login page code in the Expo app:
import * as AuthSession from 'expo-auth-session';
import { Button } from 'react-native';
export default function Login() {
const discovery = AuthSession.useAutoDiscovery("http://192.168.100.17:9011/.well-known/openid-configuration/a5673e50-cbcc-14ec-5ae3-bde9d60a1950");
const [request, response, promptAsync] = AuthSession.useAuthRequest({
clientId: process.env.FUSIONAUTH_CLIENT_ID,
scopes: ['openid', 'offline_access'],
redirectUri: AuthSession.makeRedirectUri({
path: 'oauth', // route in "app" folder in Expo router
scheme: 'myapp', // in app.json scheme is "myapp" too
}),
}, discovery);
return <Button title="Login" onPress={() => promptAsync()} />
}
This is how my app currently behaves:
This is the request object result:
{
"clientId": "7ae2dde8-5710-4f6f-b159-693a394e8eee",
"clientSecret": undefined,
"codeChallenge": "iPLWzzLvGhYvaCRbwb6-aBLdiOE8jLPEdLWWP91Xc8Q",
"codeChallengeMethod": "S256",
"codeVerifier": "c6RBW8y9mmWrqK0TRXQud7lYlPCsYS8QUQp4LZkKFZVG8ovruNzgMsDPjdGKPPkWv6bsZQtpQtcHQ24Hq0HHBLfhX36aliDIlTMumLtJzwL8Q7UI3M6rPxzv4zYpSbcD",
"extraParams": {},
"prompt": undefined,
"redirectUri": "exp://192.168.100.17:8081/--/oauth",
"responseType": "code",
"scopes": ["openid", "offline_access"],
"state": "PJIpedf69M",
"url": "http://192.168.100.17:9011/oauth2/authorize?code_challenge=iPLWzzLvGhYvaCRbwb6-aBLdiOE8jLPEdLWWP91Xc8Q&code_challenge_method=S256&redirect_uri=exp%3A%2F%2F192.168.100.17%3A8081%2F--%2Foauth&client_id=7ae2dde8-5710-4f6f-b159-693a394e8eee&response_type=code&state=PJIpedf69M&scope=openid%20offline_access",
"usePKCE": true
}
This is the response object:
{
"authentication": null,
"error": null,
"errorCode": null,
"params": {
"code": "NDyy5uMqvstnap3JIz6GWyYk1Q34ayOjPvyY3lIsayk",
"locale": "pl_PL",
"state": "PJIpedf69M",
"userState": "Authenticated"
},
"type": "success",
"url": "exp://192.168.100.17:8081/--/oauth?code=NDyy5uMqvstnap3JIz6GWyYk1Q34ayOjPvyY3lIsayk&locale=pl_PL&state=PJIpedf69M&userState=Authenticated"
}
Why is Fusion Auth not redirecting me to the redirect URL? Should I build the app using prebuild
or something else? Or should I create a development build and use a scheme like myapp://oauth
? But then, should I create an Apple Developer account for that?
英文:
I am writing an app in Expo. I am using Fusion Auth as a auth server, hosted locally.
I want to use OAuth auth flow with PKCE, app is sending a request to /authorize, then i am getting the code, auth server should redirect me to auth callback route, this auth callback route should send that code to token endpoint. However, fusion auth is not redirecting me from to auth callback route, but closes browser modal and keeps the login page active.
I am writing code with https://docs.expo.dev/versions/latest/sdk/auth-session/
this is my application Fusion Auth config
and this is my login page code in Expo app:
import * as AuthSession from 'expo-auth-session'
import { Button } from 'react-native';
export default function Login() {
const discovery = AuthSession.useAutoDiscovery("http://192.168.100.17:9011/.well-known/openid-configuration/a5673e50-cbcc-14ec-5ae3-bde9d60a1950");
const [request, response, promptAsync] = AuthSession.useAuthRequest({
clientId: process.env.FUSIONAUTH_CLIENT_ID,
scopes: ['openid', 'offline_access'],
redirectUri: AuthSession.makeRedirectUri({
path: 'oauth', // route in "app" folder in expo router
scheme: 'myapp', // in app.json scheme is "myapp" too
}),
}, discovery);
return <Button title="Login" onPress={() => promptAsync()} />
}
this is how my app currently behaves:
this is the request object result:
{
"clientId": "7ae2dde8-5710-4f6f-b159-693a394e8eee",
"clientSecret": undefined,
"codeChallenge": "iPLWzzLvGhYvaCRbwb6-aBLdiOE8jLPEdLWWP91Xc8Q",
"codeChallengeMethod": "S256",
"codeVerifier": "c6RBW8y9mmWrqK0TRXQud7lYlPCsYS8QUQp4LZkKFZVG8ovruNzgMsDPjdGKPPkWv6bsZQtpQtcHQ24Hq0HHBLfhX36aliDIlTMumLtJzwL8Q7UI3M6rPxzv4zYpSbcD",
"extraParams": {},
"prompt": undefined,
"redirectUri": "exp://192.168.100.17:8081/--/oauth",
"responseType": "code",
"scopes": ["openid", "offline_access"],
"state": "PJIpedf69M",
"url": "http://192.168.100.17:9011/oauth2/authorize?code_challenge=iPLWzzLvGhYvaCRbwb6-aBLdiOE8jLPEdLWWP91Xc8Q&code_challenge_method=S256&redirect_uri=exp%3A%2F%2F192.168.100.17%3A8081%2F--%2Foauth&client_id=7ae2dde8-5710-4f6f-b159-693a394e8eee&response_type=code&state=PJIpedf69M&scope=openid%20offline_access",
"usePKCE": true
}
this is response object:
{
"authentication": null,
"error": null,
"errorCode": null,
"params": {
"code": "NDyy5uMqvstnap3JIz6GWyYk1Q34ayOjPvyY3lIsayk",
"locale": "pl_PL",
"state": "PJIpedf69M",
"userState": "Authenticated"
},
"type": "success",
"url": "exp://192.168.100.17:8081/--/oauth?code=NDyy5uMqvstnap3JIz6GWyYk1Q34ayOjPvyY3lIsayk&locale=pl_PL&state=PJIpedf69M&userState=Authenticated"
}
Why fusion auth is not redirecting me to redirect url? Should I build app using prebuild
or something? Or create a development build and use scheme like myapp://oauth
? But then I should create an Apple Developer account for that?
答案1
得分: 0
首先,我不是一个Expo专家,但我成功地使其工作,方法是使用重定向URI的同一页面,而不是/oauth
:
export default function Login() {
const [accessToken, setAccessToken] = useState(null);
const discovery = AuthSession.useAutoDiscovery(urlToFusionAuth);
const redirectUri = AuthSession.makeRedirectUri({
scheme: 'myapp', // 我已经移除了 `path: 'oauth'`
});
console.log(redirectUri); // 仅为确保在FusionAuth中使用了正确的重定向地址
const [request, response, promptAsync] = AuthSession.useAuthRequest({
clientId: process.env.FUSIONAUTH_CLIENT_ID,
scopes: ['openid', 'offline_access'],
usePKCE: true, // 你应该使用PKCE
redirectUri,
}, discovery);
// 这在初始登录后我们被重定向回这个页面后被调用
useEffect(() => {
if (response) {
if (response.type === 'success') {
AuthSession.exchangeCodeAsync({
clientId: process.env.FUSIONAUTH_CLIENT_ID,
code: response.params.code,
extraParams: {
code_verifier: request.codeVerifier,
},
redirectUri,
}, discovery)
.then(setAccessToken)
.catch((error) => {
console.error(error);
});
return;
}
// 你应该在这里处理错误 :)
console.error(response);
}
}, [response]);
// 有条件地呈现“登录”按钮或检索到的访问令牌
return (
{(accessToken)
? <Text>{JSON.stringify(accessToken)}</Text>
: <Button disabled={!request} title="Log in" onPress={() => promptAsync()} />}
);
}
在我的示例中,我使用了PKCE,而不是在交换代码以获取访问令牌时需要提供客户端密钥,所以这是我的应用程序设置:
英文:
First of all, I'm not an Expo expert, but I was able to make it work by using the same page for the redirect URI instead of /oauth
:
export default function Login() {
const [accessToken, setAccessToken] = useState(null);
const discovery = AuthSession.useAutoDiscovery(urlToFusionAuth);
const redirectUri = AuthSession.makeRedirectUri({
scheme: 'myapp', // I've removed `path: 'oauth'`
});
console.log(redirectUri); // Just to make sure I have the right one in FusionAuth
const [request, response, promptAsync] = AuthSession.useAuthRequest({
clientId: process.env.FUSIONAUTH_CLIENT_ID,
scopes: ['openid', 'offline_access'],
usePKCE: true, // You should use PKCE
redirectUri,
}, discovery);
// This is being called after we are redirected back to this page after initial login
useEffect(() => {
if (response) {
if (response.type === 'success') {
AuthSession.exchangeCodeAsync({
clientId: process.env.FUSIONAUTH_CLIENT_ID,
code: response.params.code,
extraParams: {
code_verifier: request.codeVerifier,
},
redirectUri,
}, discovery)
.then(setAccessToken)
.catch((error) => {
console.error(error);
});
return;
}
// You should handle errors here :)
console.error(response);
}
}, [response]);
// Conditionally rendering a "Log in" button or the retrieved access token
return (
{(accessToken)
? <Text>{JSON.stringify(accessToken)}</Text>
: <Button disabled={!request} title="Log in" onPress={() => promptAsync()} />}
);
}
In my example, I'm using PKCE instead of having to provide a Client Secret when exchanging the code for an access token, so here's my application settings:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论