1658856600
我最近在单页应用程序 (SPA) 端项目中使用了 Auth0,因为我不想花时间构建所有与身份验证相关的功能,例如密码重置、注册等。令人惊讶的是,让它工作起来非常痛苦由于 HTTPS、CORS 和 localhost 问题而在本地进行。在这篇博文中,我将介绍我的最终设置,所有这些都在本地工作。
我将在我的项目中使用简单且非常标准的应用程序架构。我想将前端与后端分开,因为我不想要服务器端渲染 (SSR)。当用户访问我的网络应用程序时,我希望前端调用后端以获取任何数据。
在这种情况下,我在前端使用 React (create-react-app),在后端使用 Node express 服务器。
这是一个更新的图表,其中添加了 Auth0。现在流程有点复杂。当有人访问我的网络应用程序时,我现在想将他们重定向到 Auth0 进行注册或登录,然后再返回我的应用程序以继续用户旅程(图中的步骤 1、2 和 3)。
当用户想要编辑任何应用程序数据时,前端将附加来自 Auth0 的不记名令牌并将其与请求一起发送到后端(步骤 4 - 5)。然后,后端将通过使用该不记名令牌调用 Auth0 来验证用户是他们声称的身份,然后如果一切正常,则将数据返回到前端(步骤 6 - 8)。最后,前端将在浏览器上显示更新后的 UI(步骤 9)。
与我们开始的流程相比,此流程更加复杂,但它仍然非常标准。任何类型的身份验证服务或单点登录 (SSO) 都将涉及类似的过程。现在进入更复杂的部分 - 本地设置。
虽然 Auth0 在他们的网站上专门有一个Test Applications Locally部分,专注于本地应用程序测试,但不幸的是,就文档而言,它是非常基本的。很难确定他们指的是哪种类型的应用程序架构。据我了解,这部分似乎适用于 SSR 应用程序,而不是 SPA。还有一个关于开发中的 HTTPS的部分(我稍后会解释为什么我们需要 HTTPS),我敢肯定这不适用于上图中的架构。
长话短说,我在 Auth0 的网站上没有找到任何好的指导,所以我不得不自己打造。
如果我们的前端在 HTTP 模式下运行,我们无法使用 Auth0 进行身份验证。如果这样做,您将收到以下错误消息。
Error: auth0-spa-js must run on a secure origin.
See https://github.com/auth0/auth0-spa-js/blob/master/FAQ.md#why-do-i-get-auth0-spa-js-must-run-on-a-secure-origin for more information.
幸运的是,如果你使用 create react app 很容易解决这个问题,它就像HTTPS=true
你的启动命令一样简单,例如HTTPS=true npm start
. 在这里查看更多信息。
这样做可以解决 Auth0 的问题,但现在 Chrome 会抱怨我们的 HTTPS 前端现在正在向后端发送非安全请求 (HTTP)。所以接下来我们需要在 HTTPS 模式下运行后端。要使用 Express 执行此操作,我们需要生成一些证书,我建议使用mkcert。这将输出两个文件,一个密钥和一个证书,我们都需要在 HTTPS 模式下运行 Express 服务器。然后,您将执行以下操作。
import fs from "fs";
import https from "https";
...
const privateKey = fs.readFileSync("../../key.pem", "utf8");
const certificate = fs.readFileSync("../../cert.pem", "utf8");
const credentials = { key: privateKey, cert: certificate };
...
const httpsServer = https.createServer(credentials, app);
httpsServer.listen(process.env.PORT || "8000");
好吧,现在我们有了这些证书,我们不妨在前端使用它们。再次创建响应应用程序来救援!我们需要做的就是在我们的.env
文件中包含以下内容,并react-scripts
在开发模式下自动获取它。
SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem
要执行第二张图中的步骤 5,我们需要使用getAccessTokenSilently()
(我再次使用 React,您的里程可能会有所不同)提取我们需要传递给后端的不记名令牌。但是,这将触发同意检查(即使这是第一方应用程序!),如果我们在其上运行,[localhost](http://localhost)
它将静默失败。您可以在用户同意和第三方应用程序页面上阅读更多相关信息。
如果您使用的是 mac 或 linux 则编辑/etc/host
,如果您是 windows则编辑C:\Windows\System32\Drivers\etc\hosts
。您可以替换[localhost](http://localhost)
为,[example.site](http://example.site)
但我更喜欢保留两者,因为我也使用假设的代码库localhost
。
127.0.0.1 localhost example.site
本地环境上的 CORS 实在是太令人沮丧了。如果您按照上面的说明进行操作,那么希望在您的 Express 服务器中,您只需添加以下内容,一切都会正常。
import cors from "cors";
...
app.use(cors());
或者,考虑添加一些白名单逻辑。
import cors from "cors";
...
const whitelist = process.env.ORIGIN_WHITELIST_URL || "https://production.site";
const corsOptions = {
origin: function (origin: any, callback: any) {
if (whitelist.includes(origin) || !origin) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
};
...
app.use(cors(corsOptions));
如果它仍然不起作用,请尝试允许任何来源。当然,这是不安全的,所以稍后再回来并对其进行防弹生产。
import cors from "cors";
...
const corsOptions = {
origin: '*',
};
...
app.use(cors(corsOptions));
...
如果您正在考虑使用 Auth0,我遇到了另一个名为Magic的服务,它似乎提供了更好的整体开发体验。他们的本地环境设置好得令人难以置信,请在此处查看。然而,我最后选择 Auth0 的原因是因为他们慷慨的免费套餐最多允许 1000 个活跃用户。相比之下,Magic 根据用户登录次数收费,并且没有免费限额。
1658856600
我最近在单页应用程序 (SPA) 端项目中使用了 Auth0,因为我不想花时间构建所有与身份验证相关的功能,例如密码重置、注册等。令人惊讶的是,让它工作起来非常痛苦由于 HTTPS、CORS 和 localhost 问题而在本地进行。在这篇博文中,我将介绍我的最终设置,所有这些都在本地工作。
我将在我的项目中使用简单且非常标准的应用程序架构。我想将前端与后端分开,因为我不想要服务器端渲染 (SSR)。当用户访问我的网络应用程序时,我希望前端调用后端以获取任何数据。
在这种情况下,我在前端使用 React (create-react-app),在后端使用 Node express 服务器。
这是一个更新的图表,其中添加了 Auth0。现在流程有点复杂。当有人访问我的网络应用程序时,我现在想将他们重定向到 Auth0 进行注册或登录,然后再返回我的应用程序以继续用户旅程(图中的步骤 1、2 和 3)。
当用户想要编辑任何应用程序数据时,前端将附加来自 Auth0 的不记名令牌并将其与请求一起发送到后端(步骤 4 - 5)。然后,后端将通过使用该不记名令牌调用 Auth0 来验证用户是他们声称的身份,然后如果一切正常,则将数据返回到前端(步骤 6 - 8)。最后,前端将在浏览器上显示更新后的 UI(步骤 9)。
与我们开始的流程相比,此流程更加复杂,但它仍然非常标准。任何类型的身份验证服务或单点登录 (SSO) 都将涉及类似的过程。现在进入更复杂的部分 - 本地设置。
虽然 Auth0 在他们的网站上专门有一个Test Applications Locally部分,专注于本地应用程序测试,但不幸的是,就文档而言,它是非常基本的。很难确定他们指的是哪种类型的应用程序架构。据我了解,这部分似乎适用于 SSR 应用程序,而不是 SPA。还有一个关于开发中的 HTTPS的部分(我稍后会解释为什么我们需要 HTTPS),我敢肯定这不适用于上图中的架构。
长话短说,我在 Auth0 的网站上没有找到任何好的指导,所以我不得不自己打造。
如果我们的前端在 HTTP 模式下运行,我们无法使用 Auth0 进行身份验证。如果这样做,您将收到以下错误消息。
Error: auth0-spa-js must run on a secure origin.
See https://github.com/auth0/auth0-spa-js/blob/master/FAQ.md#why-do-i-get-auth0-spa-js-must-run-on-a-secure-origin for more information.
幸运的是,如果你使用 create react app 很容易解决这个问题,它就像HTTPS=true
你的启动命令一样简单,例如HTTPS=true npm start
. 在这里查看更多信息。
这样做可以解决 Auth0 的问题,但现在 Chrome 会抱怨我们的 HTTPS 前端现在正在向后端发送非安全请求 (HTTP)。所以接下来我们需要在 HTTPS 模式下运行后端。要使用 Express 执行此操作,我们需要生成一些证书,我建议使用mkcert。这将输出两个文件,一个密钥和一个证书,我们都需要在 HTTPS 模式下运行 Express 服务器。然后,您将执行以下操作。
import fs from "fs";
import https from "https";
...
const privateKey = fs.readFileSync("../../key.pem", "utf8");
const certificate = fs.readFileSync("../../cert.pem", "utf8");
const credentials = { key: privateKey, cert: certificate };
...
const httpsServer = https.createServer(credentials, app);
httpsServer.listen(process.env.PORT || "8000");
好吧,现在我们有了这些证书,我们不妨在前端使用它们。再次创建响应应用程序来救援!我们需要做的就是在我们的.env
文件中包含以下内容,并react-scripts
在开发模式下自动获取它。
SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem
要执行第二张图中的步骤 5,我们需要使用getAccessTokenSilently()
(我再次使用 React,您的里程可能会有所不同)提取我们需要传递给后端的不记名令牌。但是,这将触发同意检查(即使这是第一方应用程序!),如果我们在其上运行,[localhost](http://localhost)
它将静默失败。您可以在用户同意和第三方应用程序页面上阅读更多相关信息。
如果您使用的是 mac 或 linux 则编辑/etc/host
,如果您是 windows则编辑C:\Windows\System32\Drivers\etc\hosts
。您可以替换[localhost](http://localhost)
为,[example.site](http://example.site)
但我更喜欢保留两者,因为我也使用假设的代码库localhost
。
127.0.0.1 localhost example.site
本地环境上的 CORS 实在是太令人沮丧了。如果您按照上面的说明进行操作,那么希望在您的 Express 服务器中,您只需添加以下内容,一切都会正常。
import cors from "cors";
...
app.use(cors());
或者,考虑添加一些白名单逻辑。
import cors from "cors";
...
const whitelist = process.env.ORIGIN_WHITELIST_URL || "https://production.site";
const corsOptions = {
origin: function (origin: any, callback: any) {
if (whitelist.includes(origin) || !origin) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
};
...
app.use(cors(corsOptions));
如果它仍然不起作用,请尝试允许任何来源。当然,这是不安全的,所以稍后再回来并对其进行防弹生产。
import cors from "cors";
...
const corsOptions = {
origin: '*',
};
...
app.use(cors(corsOptions));
...
如果您正在考虑使用 Auth0,我遇到了另一个名为Magic的服务,它似乎提供了更好的整体开发体验。他们的本地环境设置好得令人难以置信,请在此处查看。然而,我最后选择 Auth0 的原因是因为他们慷慨的免费套餐最多允许 1000 个活跃用户。相比之下,Magic 根据用户登录次数收费,并且没有免费限额。
1596826140
How often do you feel that there is something wrong with the email address of that new customer? The username and the domain look suspicious. With the new risk assessment features of the Email Verification API, you can get enough insights to make informed decisions about your users in real-time.
There is a rising wave of abusers that sign up to services offering freemium or free-trial. Typically they want to exploit the resource you offer (compute, streaming, APIs, etc). The tension lies between converting more vs stopping these abusers.
One way to stop them, without introducing much friction, is to verify if their email is legitimate (without sending all users an email). This is what the Auth0 Signals Email Verification API provides.
The Auth0 Signals API is a standalone free service for the community. The service consists of an HTTP API that allows you to detect the reputation of an Email address or the IP address. The API checks the Email and/or IP address against several public denylists to evaluate its reputation. It responds with data about the originator and a score indicating the reliability level of the Email or IP address. Having this information enables you to detect malicious activities proactively.
Join the Auth0 Hackathon to win $10,000 in prizes and swag!
The Email Verification signal provides a continually curated and accurate Email reputation data. It takes the hard work out of consuming Open-Source Intelligence (OSINT) by curating, parsing, and normalizing numerous denylists. Auth0 uses this data to protect its own service.
There are two main use cases for this API:
Auth0 Email verification signal enables all users to obtain a score that indicates the risk level of an analyzed Email address. The overall process involves an in-depth analysis of each email, combining several validation techniques based on custom-built algorithms scoring the legitimacy of an email. Clean and valid email addresses will have a neutral score. Suspicious addresses will have a negative rating: the more negative the score, the more probability of being an address with a low reputation.
#auth0 #api #auth0 signals
1661330940
The goal of {auth0}
is to implement an authentication scheme to Shiny using OAuth Apps through the freemium service Auth0.
You can install {auth0}
from CRAN with:
install.packages("auth0")
You can also install the development version from github with:
# install.packages("devtools")
remotes::install_github("curso-r/auth0")
To create your authenticated shiny app, you need to follow the five steps below.
After logging into Auth0, you will see a page like this:
http://localhost:8080
to the "Allowed Callback URLs", "Allowed Web Origins" and "Allowed Logout URLs".http://localhost:8080
to another port.fooBar
) in "Allowed Web Origins".Now let's go to R!
_auth0.yml
fileauth0::use_auth0()
:auth0::use_auth0()
path=
parameter. See ?auth0::use_auth0
for details._auth0.yml
file should be like this:name: myApp
remote_url: ''
auth0_config:
api_url: !expr paste0('https://', Sys.getenv("AUTH0_USER"), '.auth0.com')
credentials:
key: !expr Sys.getenv("AUTH0_KEY")
secret: !expr Sys.getenv("AUTH0_SECRET")
usethis::edit_r_environ()
and add these three environment variables:AUTH0_USER=johndoe
AUTH0_KEY=5wugt0W...
AUTH0_SECRET=rcaJ0p8...
There's how you identify each of them (see the image below):
AUTH0_USER
is your username, which can be found on the top corner of the site.AUTH0_KEY
is your Client ID, which can be copied from inside the app page.AUTH0_SECRET
is your Client Secret, which can be copied from the app page.More about environment variables here. You can also fill these information directly in the _auth0.yml
file (see below). If you do so, don't forget to save the _auth0.yml
file after editing it.
app.R
file, like this:library(shiny)
ui <- fluidPage(
fluidRow(plotOutput("plot"))
)
server <- function(input, output, session) {
output$plot <- renderPlot({
plot(1:10)
})
}
# note that here we're using a different version of shinyApp!
auth0::shinyAppAuth0(ui, server)
Note: If you want to use a different path to the auth0
configuration file, you can either pass it to shinyAppAuth0()
or set the auth0_config_file
option by running options(auth0_config_file = "path/to/file")
.
You can try your app running
options(shiny.port = 8080)
shiny::runApp("app/directory/")
If everything is OK, you should be forwarded to a login page and, after logging in or signing up, you'll be redirected to your app.
If you are running your app in a remote server like shinyapps.io or your own server, and if your app is in a subfolder of the host (like https://johndoe.shinyapps.io/fooBar), you must include your remote URL in the remote_url
parameter in the _auth0.yml
file.
You can also force {auth0}
to use the local URL setting options(auth0_local = TRUE)
. This can useful if you're running an app inside a Docker container.
If you are using {auth0}
for just one shiny app or you are running many apps for the same user database, the recommended workflow is using the environment variables AUTH0_KEY
and AUTH0_SECRET
.
However, if you are running many shiny apps and want to use different login settings, you must create many Auth0 apps. Hence, you'll have many Cliend IDs and Client Secrets to use. n this case, global environment variables will be unproductive because you'll need to change them every time you change the app you are developing.
There are two options in this case:
usethis::edit_r_environ("project")
.The best option in this case is to simply add the Client ID and Secret directly in the _auth0.yml
file:
name: myApp
remote_url: ''
auth0_config:
api_url: https://<USERNAME>.auth0.com
credentials:
key: <CLIENT_ID>
secret: <CLIENT_SECRET>
Example:
name: myApp
remote_url: ''
auth0_config:
api_url: https://johndoe.auth0.com
credentials:
key: cetQp0e7bdTNGrkrHpuF8gObMVl8vu
secret: C6GHFa22mfliojqPyKP_5K0ml4TituWrOhYvLdTa7veIyEU3Q10R_-If-7Sh6Tc
Although possible, the latter option is less secure and consequently not recommended because it's easy to forget passwords there and commit them in public repositories, for example.
ui.R
/server.R
To make {auth0}
work using an ui.R
/server.R
framework, you'll need to wrap your ui
object/function with auth0_ui()
and your server
function with auth0_server()
. Here's a small working example:
library(shiny)
library(auth0)
auth0_ui(fluidPage(logoutButton()))
library(auth0)
auth0_server(function(input, output, session) {})
{auth0}
will try to find the _auth0.yml
using the same strategy than the app.R
framework: first from options(auth0_config_file = "path/to/file")
and then fixing "./_auth0.yml"
. Both auth0_ui()
and auth0_server()
have a info=
parameter where you can pass either the path of the _auth0.yml
file or the object returned by auth0_info()
function.
To authorize a client to make API calls against a remote server, the authorization request should include an audience
parameter (Auth0 documentation).
To do this with {auth0}
, add an audience
parameter to the auth0_config
section of your _auth0.yml
file. For example:
name: myApp
remote_url: ''
auth0_config:
api_url: !expr paste0('https://', Sys.getenv("AUTH0_USER"), '.auth0.com')
audience: https://example.com/api
credentials:
key: !expr Sys.getenv("AUTH0_KEY")
secret: !expr Sys.getenv("AUTH0_SECRET")
When an audience
parameter is included in the request, the access token returned by Auth0 will be a JWT access token rather than an opaque access token. The client must include the access token with API requests to authenticate the requests.
Because RStudio is specialized in standard shiny apps, some features do not work as expected when using {auth0}
. The main issues are is that you must run the app in a real browser, like Chrome or Firefox. If you use the RStudio Viewer or run the app in a RStudio window, the app will show a blank page and won't work.
If you're using a version lower than 1.2 in RStudio, the "Run App" button may not appear in the right corner of the app.R script. That's because RStudio searches for the "shinyApp(" term in the code to identify a shiny app.
Since v0.2.0, auth0
supports shiny's state bookmarking, but because of URL parsing issues, bookmarking only works with server storage. To activate this feature, you must call the app with the following lines in your app.R
file:
enableBookmarking(store = "server")
shinyAppAuth0(ui, server)
Also note that Auth0 adds code
and state
to the URL query parameters.
This solution works normally in the ui.R
/server.R
framework.
You can manage user access from the Users panel in Auth0. To create a user, click on "+ Create users".
You can also use many different OAuth providers like Google, Facebook, Github etc. To configure them, go to the Connections tab.
In the near future, our plan is to implement Auth0's API in R so that you can manage your app using R.
After a user logs in, it's possible to access the current user's information using the session$userData$auth0_info
reactive object. The Auth0 token can be accessed using session$userData$auth0_credentials
. Here is a small example:
library(shiny)
library(auth0)
# simple UI with user info
ui <- fluidPage(
verbatimTextOutput("user_info")
verbatimTextOutput("credential_info")
)
server <- function(input, output, session) {
# print user info
output$user_info <- renderPrint({
session$userData$auth0_info
})
output$credential_info <- renderPrint({
session$userData$auth0_credentials
})
}
shinyAppAuth0(ui, server)
You should see objects containing the user and credential info.
User info
$sub
[1] "auth0|5c06a3aa119c392e85234f"
$nickname
[1] "jtrecenti"
$name
[1] "jtrecenti@email.com"
$picture
[1] "https://s.gravatar.com/avatar/1f344274fc21315479d2f2147b9d8614?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fjt.png"
$updated_at
[1] "2019-02-13T10:33:06.141Z"
Note that the sub
field is unique and can be used for many purposes, like creating customized apps for different users.
Credential info (abridged)
$access_token
[1] "y5Yv..."
$id_token
[1] "eyJ0..."
$scope
[1] "openid profile"
$expires_in
[1] 86400
$token_type
[1] "Bearer"
The id_token
may be used with applications that require an Authorization
header with each web request.
If you're running {auth0}
using ui.R/server.R
framework and you want to access logged information, you'll need to use the same object returned auth0_info()
function in both auth0_ui()
and auth0_server()
.
This is possible using the global.R
file. For example:
a0_info <- auth0::auth0_info()
library(shiny)
library(auth0)
auth0_ui(fluidPage(), info = a0_info)
library(auth0)
auth0_server(function(input, output, session) {
observe({
print(session$userData$auth0_info)
})
}, info = a0_info)
You can add a logout button to your app using logoutButton()
.
library(shiny)
library(auth0)
# simple UI with logout button
ui <- fluidPage(logoutButton())
server <- function(input, output, session) {}
shinyAppAuth0(ui, server)
Auth0 is a freemium service. The free account lets you have up to 7000 connections in one month and two types of social connections. You can check all the plans here.
This package is not provided nor endorsed by Auth0 Inc. Use it at your own risk.
Also, I am NOT a security expert, and as Bob Rudis pointed out, adding the word "secure" on something has broad implications of efficacy and completeness. So this package may be lying when it tells it's secure.
If you're a security expert and liked the idea of this package, please consider testing it. We'll be really, really grateful for any help.
{auth0}
0.2.0config_file
.shinyAppDirAuth0()
function to work as shiny::shinyAppDir()
(Issue #21).ui.R
/server.R
apps.{auth0}
0.3.0{auth0}
API functions to manage users and login options throusgh R.Author: Curso-r
Source Code: https://github.com/curso-r/auth0
License: View license
1606809180
In this episode of Mission Briefing, Sam Julien (@samjulien) from Auth0 walks Kurt Kemple (@kurtkemple) through securing a GraphQL API and React.
#graphql #auth0
1608707165
In this article, we take a deep look at how databases that behave like APIs increase developer productivity.
Fauna is a flexible, developer-friendly, transactional database delivered to as a secure, web-native API that eliminates the need for database provisioning, sharding, or replication. Integrating Auth0 with Fauna is easier than ever now, thanks to the recent third-party integration.
#security #fauna #auth0 #web-development #developer