首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用React和Door门将来实现PKCE OAuth2?

如何用React和Door门将来实现PKCE OAuth2?
EN

Stack Overflow用户
提问于 2022-04-28 16:27:46
回答 1查看 597关注 0票数 0

我创建了一个Rails应用程序,其中有Devise和Doorkeeper,用于身份验证,并将其作为一个API使用OAuth2 PKCE作为一个React。

预期行为:

当我用在B中接收的代码发送POST请求时,返回身份验证令牌

实际行为

它返回此错误,而不是返回令牌:

代码语言:javascript
复制
{
  "error": "invalid_grant",
  "error_description": "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
}

如何再现错误:

  • 对于:
  1. expo init auth-pkce-app -->选择Typescrit空白模板
  2. expo install expo-linking expo-web-browser js-sha256
  3. 然后将App.tsx中的代码替换为:
代码语言:javascript
复制
import React, { useEffect, useState } from "react";
import { Button, StyleSheet, Text, View } from "react-native";
import * as Linking from "expo-linking";
import * as WebBrowser from "expo-web-browser";
import { sha256 } from "js-sha256";

const CLIENT_ID = "Ox8_PbOB3g9kBy1HsuEWm6ieePS35jQWcaP_a2D6EmU";
const CLIENT_SECRET = "Z2TJo0AZeseyVvpua7piCPTBXA2v2pIAI3aBKpP1n8c";

const CODE_VERIFIER = "Antante";
const code_challenge = sha256(CODE_VERIFIER);
const code_chanllenge_method = "S256";
const AUTHORIZE_URL =
  `http://localhost:3000/oauth/authorize` +
  `?client_id=${CLIENT_ID}` +
  `&redirect_uri=${Linking.createURL("")}` +
  `&response_type=code` +
  `&scope=write` +
  `&code_challenge=${code_challenge}` +
  `&code_challenge_method=${code_chanllenge_method}`;
  
const TOKEN_URL =
  "http://localhost:3000/oauth/token" +
  `?client_id=${CLIENT_ID}` +
  `&client_secret=${CLIENT_SECRET}` +
  "&grant_type=authorization_code" +
  `&code_verifier=${CODE_VERIFIER}` +
  `&redirect_uri=${Linking.createURL("")}`;

const App: React.FC<{}> = () => {
  const [state, setState] = useState<{
    redirectData?: Linking.ParsedURL | null;
    result?: WebBrowser.WebBrowserAuthSessionResult;
  }>({
    redirectData: null,
  });

  useEffect(() => {
    fetchToken();
  }, [state]);

  const fetchToken = async () => {
    try {
      const response = await fetch(
        TOKEN_URL + `&code=${state.redirectData?.queryParams.code}`,
        {
          method: "POST",
        }
      );
      const data = await response.json();
      console.log(data);
    } catch (err) {
      console.log(err);
    }
  };

  const openAuthSessionAsync = async () => {
    try {
      let result = await WebBrowser.openAuthSessionAsync(
        AUTHORIZE_URL,
        Linking.createURL("")
      );
      let redirectData;
      if (result.type === "success") {
        redirectData = Linking.parse(result.url);
      }
      setState({ result, redirectData });
    } catch (error) {
      alert(error);
      console.log(error);
    }
  };

  const maybeRenderRedirectData = () => {
    if (!state.redirectData) {
      return;
    }
    console.log(state.redirectData);

    return (
      <Text style={{ marginTop: 30 }}>
        {JSON.stringify(state.redirectData)}
      </Text>
    );
  };

  return (
    <View style={styles.container}>
      <Button onPress={openAuthSessionAsync} title="Go to login" />
      <Text>{Linking.createURL("")}</Text>
      {maybeRenderRedirectData()}
    </View>
  );
};

export default App;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
    paddingBottom: 40,
  },
  header: {
    fontSize: 25,
    marginBottom: 25,
  },
});
  1. 使用yarn start和<<启动应用程序,请记住重定向链接,按钮标记为“Go to login”>>
  • 用于Rails应用程序和
  1. git clone git@github.com:dogaruemiliano/pkce-auth.git rails-pkce-auth
  2. bundle install
  3. 转到db/seeds.rb,将文件顶部的链接(REDIRECT_URI = 'exp://192.168.0.107:19000')替换为我们前面提到的链接。
  4. rails db:migrate db:seed

^这将在终端中输出Door蛋::应用程序的详细信息(id,保密)

  1. rails g webpacker:install
  2. 钢轨
EN

回答 1

Stack Overflow用户

发布于 2022-07-21 13:12:49

问题在于sha256编码。在您的示例中从js-sha256返回的是基于十六进制的,但是我们需要匹配来自看门人的base64编码sha256

代码语言:javascript
复制
def generate_code_challenge(code_verifier)
  Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier), padding: false)
end

通过使用expo-crypto可能更容易实现这一点。

代码语言:javascript
复制
var code_challenge = await Crypto.digestStringAsync(
  Crypto.CryptoDigestAlgorithm.SHA256,
  CODE_VERIFIER,
  {encoding: Crypto.CryptoEncoding.BASE64}
).then(
  digest => digest.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
)

希望能帮上忙。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72047234

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档