如何使用 auth0 正确验证来自 React SPA 的 API 调用?
How do I properly authenticate an API call from a React SPA using auth0?
我认为这应该相对简单,但我一定遗漏了一些简单的东西。我有一个用户登录到一个单页应用程序,一个 React 应用程序 运行 on localhost:3000(使用 yarn start)。
我在 localhost:8080 上有一个内置的后端 API 运行。我想使用 auth0 将我的 API 设为私有。我有前端登录部分工作。我似乎无法正确验证 API 请求。在我的 React 代码中,我有以下内容:
const auth0 = await createAuth0Client({
domain: 'mydomain.auth0.com',
client_id: 'my_client_id_for_react_spa'
});
//just making sure this is true. It always is.
const isAuthenticated = await auth0.isAuthenticated();
console.log("Is Authenticated: ", isAuthenticated);
const token = await auth0.getTokenSilently();
console.log("Token: ", token);
try {
const result = await fetch('http://localhost:8080/api/private', {
method: 'GET',
mode: 'no-cors',
headers: {
Authorization: 'Bearer ' + token,
}
});
console.log("Result: ", result);
} catch (e) {
console.log("Error: ", e);
}
我收到了 401 响应。怎么会这样?我已通过身份验证并随请求一起发送令牌。显然我错过了一些东西。
编辑
这是执行代码:
import (
//...other stuff i need
jwtmiddleware "github.com/auth0/go-jwt-middleware"
"github.com/codegangsta/negroni"
jwt "github.com/dgrijalva/jwt-go"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
r := mux.NewRouter()
jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
// Verify 'aud' claim
aud := "https://api.mydomain.com"
checkAud := token.Claims.(jwt.MapClaims).VerifyAudience(aud, false)
if !checkAud {
log.Println("Invalid audience")
return token, errors.New("Invalid audience.")
}
// Verify 'iss' claim
iss := "https://mydomain.auth0.com/"
checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(iss, false)
if !checkIss {
log.Println("Invalid issuer")
return token, errors.New("Invalid issuer.")
}
cert, err := getPemCert(token)
if err != nil {
panic(err.Error())
}
result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert))
return result, nil
},
SigningMethod: jwt.SigningMethodRS256,
})
t := testAPIEndpoint{}
n := negroni.New(negroni.HandlerFunc(jwtMiddleware.HandlerWithNext), negroni.Wrap(t))
r.Handle("/api/private", n)
// This route is always accessible
r.Handle("/api/public", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
message := "Hello from a public endpoint! You don't need to be authenticated to see this."
responseJSON(message, w, http.StatusOK)
}))
allowedOrigins := handlers.AllowedOrigins([]string{"http://localhost:3000"})
log.Fatal(http.ListenAndServe(":8080", handlers.CORS(allowedOrigins)(r)))
我认为您在调用 /authorize 端点时没有包含 audience 参数。因此,您收到的是不透明令牌而不是 JWT 令牌。
https://auth0.com/docs/tokens/access-tokens#access-token-structure
尝试以下:
auth0 = await createAuth0Client({
domain: config.domain,
client_id: config.clientId,
audience: config.audience // API identifier (https://api.mydomain.com)
});
因此,您将收到一个带有 API 授权信息的有效 JWT 令牌。尝试解码 https://jwt.io 中的令牌以查看令牌结构。确保令牌已获得 aud 声明。
https://auth0.com/docs/tokens/jwt-claims#reserved-claims
我想您现在可以调用 API 端点了。
https://auth0.com/docs/quickstart/spa/vanillajs/02-calling-an-api#calling-the-api
我认为这应该相对简单,但我一定遗漏了一些简单的东西。我有一个用户登录到一个单页应用程序,一个 React 应用程序 运行 on localhost:3000(使用 yarn start)。
我在 localhost:8080 上有一个内置的后端 API 运行。我想使用 auth0 将我的 API 设为私有。我有前端登录部分工作。我似乎无法正确验证 API 请求。在我的 React 代码中,我有以下内容:
const auth0 = await createAuth0Client({
domain: 'mydomain.auth0.com',
client_id: 'my_client_id_for_react_spa'
});
//just making sure this is true. It always is.
const isAuthenticated = await auth0.isAuthenticated();
console.log("Is Authenticated: ", isAuthenticated);
const token = await auth0.getTokenSilently();
console.log("Token: ", token);
try {
const result = await fetch('http://localhost:8080/api/private', {
method: 'GET',
mode: 'no-cors',
headers: {
Authorization: 'Bearer ' + token,
}
});
console.log("Result: ", result);
} catch (e) {
console.log("Error: ", e);
}
我收到了 401 响应。怎么会这样?我已通过身份验证并随请求一起发送令牌。显然我错过了一些东西。
编辑
这是执行代码:
import (
//...other stuff i need
jwtmiddleware "github.com/auth0/go-jwt-middleware"
"github.com/codegangsta/negroni"
jwt "github.com/dgrijalva/jwt-go"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
r := mux.NewRouter()
jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
// Verify 'aud' claim
aud := "https://api.mydomain.com"
checkAud := token.Claims.(jwt.MapClaims).VerifyAudience(aud, false)
if !checkAud {
log.Println("Invalid audience")
return token, errors.New("Invalid audience.")
}
// Verify 'iss' claim
iss := "https://mydomain.auth0.com/"
checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(iss, false)
if !checkIss {
log.Println("Invalid issuer")
return token, errors.New("Invalid issuer.")
}
cert, err := getPemCert(token)
if err != nil {
panic(err.Error())
}
result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert))
return result, nil
},
SigningMethod: jwt.SigningMethodRS256,
})
t := testAPIEndpoint{}
n := negroni.New(negroni.HandlerFunc(jwtMiddleware.HandlerWithNext), negroni.Wrap(t))
r.Handle("/api/private", n)
// This route is always accessible
r.Handle("/api/public", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
message := "Hello from a public endpoint! You don't need to be authenticated to see this."
responseJSON(message, w, http.StatusOK)
}))
allowedOrigins := handlers.AllowedOrigins([]string{"http://localhost:3000"})
log.Fatal(http.ListenAndServe(":8080", handlers.CORS(allowedOrigins)(r)))
我认为您在调用 /authorize 端点时没有包含 audience 参数。因此,您收到的是不透明令牌而不是 JWT 令牌。
https://auth0.com/docs/tokens/access-tokens#access-token-structure
尝试以下:
auth0 = await createAuth0Client({
domain: config.domain,
client_id: config.clientId,
audience: config.audience // API identifier (https://api.mydomain.com)
});
因此,您将收到一个带有 API 授权信息的有效 JWT 令牌。尝试解码 https://jwt.io 中的令牌以查看令牌结构。确保令牌已获得 aud 声明。 https://auth0.com/docs/tokens/jwt-claims#reserved-claims
我想您现在可以调用 API 端点了。 https://auth0.com/docs/quickstart/spa/vanillajs/02-calling-an-api#calling-the-api