1679017587
Learn how to secure a React application by implementing user authentication with Auth0. A complete guide to React User Authentication with Auth0
Authentication shouldn't take more than a few minutes to set up! In this video, we are going to use Auth0 to add authentication to a React application. We'll cover creating the application in the Auth0 dashboard, installing and configuring the SDK in a starter project, adding login/logout, and displaying user profile information!
Full React Authentication Guide - https://auth0.com/blog/complete-guide-to-react-user-authentication/
Auth0 React SDK - https://github.com/auth0/auth0-react
#react #auth0
1675928668
Learn how to secure a Flask API with Auth0. Build Secure APIs with Flask and Auth0. This tutorial shows how to implementation of OAuth2 for Python and Flask using Auth0. Built a secure API with three levels of access – public access, private access and privately-scoped access.
APIs are at the heart of modern development. They support all kinds of systems, from mobile, web, and desktop applications, to IoT devices and self-driving cars. They are a bridge between your clients and your application logic and storage.
This central access point to your application’s data raises the question: how can you provide access to the information to those who need it while denying access to unauthorized requests?
The industry has provided several protocols and best practices for securing APIs. Today we will focus on OAuth2, one of the most popular options for authorizing clients into our APIs.
But how do we implement OAuth2? There are two ways to go about it:
In this article, I will walk you through an implementation of OAuth2 for Python and Flask using Auth0 as our identity provider. But first, we are going to discuss the do-it-yourself approach.
For a few years now, I wanted to give back to the community that helped me so much by teaching me programming and helping me progress in my search for knowledge. I always thought that a great way to contribute was by having my own blog, a thing that I tried more than a few times and failed.
But where did I fail? Instead of focusing on writing, I tried to build my own blog engine because it’s in my nature. It’s what developers do. They love to build.
But why do I mention that here? Because many fall into the same trap when building APIs. Let me explain with an example.
Bob is a great developer, and he has this great idea for a ToDo app that can be the next big thing. Bob is very aware that for a successful implementation, users can only access their own data.
Here is bob’s application timeline:
Let’s talk about what happened. Bob spent the first few sprints not building his app but building the basic blocks, like logging in and out functionality, email notifications, and so on. This valuable time could have been spent differently, but what happens next is more concerning.
Bob’s backlog starts to fill in. Now, he needs to improvise a 2-factor authentication method, add single sign-on, and more non-product-related functions that could potentially delay his product.
And there’s still a big question to be answered: did Bob implement all the security mechanisms correctly? A critical error could expose all the user’s information to outsiders.
What Bob did is what I did with my blog many times. Sometimes, it's helpful to rely on 3rd parties if we want to get things done right.
Today, hackers and attacks have become so sophisticated that security is not a trivial factor anymore. It is a complicated system on its own, and it is often best to leave its implementation to experts – not only so it’s done right, but also so we can focus on what matters: building our applications and APIs.
Auth0 is a leading authentication and authorization provider, but let’s see how it can help Bob (or you) build a better app:
Time to get practical. First, make sure you have an Auth0 account. If not, you can create one here for free.
There is still one more thing we have to do before we start coding. Head over to the APIs section of your Auth0 dashboard and click on the “Create API” button. After that, fill in the form with your details. However, make sure you select RS256
as the Signing Algorithm
.
Your form should look like the following:
Creating the API – image showing fields to fill out
The API details page opens after successfully creating an API. Keep that tab open, as it contains information we need to set up our application. If you close it, don’t worry, you can always access it again.
Because we will focus on the security aspects only, we will take a few shortcuts when building our demo API. However, when developing actual APIs, please follow best practices for Flask APIs.
First, install the following dependencies for setting up Flask and authenticating users.
pipenv install flask python-dotenv python-jose flask-cors six
Our API will be straightforward. It will consist of only three endpoints, all of which, for now, will be publicly accessible. However, we will fix that soon. Here are our endpoints:
/
(public endpoint)/user
(requires a logged in user)/admin
(only users of admin role)Let’s get to it:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index_view():
"""
Default endpoint, it is public and can be accessed by anyone
"""
return jsonify(msg="Hello world!")
@app.route("/user")
def user_view():
"""
User endpoint, can only be accessed by an authorized user
"""
return jsonify(msg="Hello user!")
@app.route("/admin")
def admin_view():
"""
Admin endpoint, can only be accessed by an admin
"""
return jsonify(msg="Hello admin!")
Very simple right? Let’s run it:
~ pipenv run flask run
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
And if we access our endpoint:
~ curl -i http://localhost:5000
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:24:57 GMT
{"msg":"Hello world!"}
~ curl -i http://localhost:5000/user
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 22
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:25:42 GMT
{"msg":"Hello user!"}
~ curl -i http://localhost:5000/admin
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:26:18 GMT
{"msg":"Hello admin!"}
As we are using OAuth, we will authenticate requests by validating an access token in JWT format. We'll send it to the API on each request as part of the HTTP headers.
As mentioned in the previous section, our API needs to be aware and will require information from our Auth0 dashboard. So head back to your API details page, and grab two different values.
First, the API Identifier:
This is the value required when the API is created. You can also get it from your API details page:
How to find the API identifier on the API details page
Next, Auth0 domain:
Unless you're using a custom domain, this value will be [TENANT_NAME].auth0.com
, and you can grab it from the Test
tab (make sure not to include https://
and the last forward slash /
).
Getting the Auth0 domain
Next, pass those values into variables so they can be used in the validation functions.
AUTH0_DOMAIN = 'YOUR-AUTH0-DOMAIN'
API_IDENTIFIER = 'API-IDENTIFIER'
ALGORITHMS = ["RS256"]
During this implementation, we will need a way to throw errors when authentication fails. So we will use the following helpers for those needs:
class AuthError(Exception):
def __init__(self, error, status_code):
self.error = error
self.status_code = status_code
@app.errorhandler(AuthError)
def handle_auth_error(ex):
response = jsonify(ex.error)
response.status_code = ex.status_code
return response
The first step to validate a user is to retrieve the JWT token from the HTTP headers. This is very simple, but there are a few things to keep in mind. Here is an example of it:
def get_token_auth_header():
"""
Obtains the Access Token from the Authorization Header
"""
auth = request.headers.get("Authorization", None)
if not auth:
raise AuthError({"code": "authorization_header_missing",
"description":
"Authorization header is expected"}, 401)
parts = auth.split()
if parts[0].lower() != "bearer":
raise AuthError({"code": "invalid_header",
"description":
"Authorization header must start with"
" Bearer"}, 401)
elif len(parts) == 1:
raise AuthError({"code": "invalid_header",
"description": "Token not found"}, 401)
elif len(parts) > 2:
raise AuthError({"code": "invalid_header",
"description":
"Authorization header must be"
" Bearer token"}, 401)
token = parts[1]
return token
Having a token passed to our API is a good sign, but it doesn’t mean that it is a valid client. We need to check the token signature.
Since the logic to require authentication can be used for more than one endpoint, it would be important to abstract it and make it easily accessible for developers to implement. The best way to do this is by using decorators.
def requires_auth(f):
"""
Determines if the Access Token is valid
"""
@wraps(f)
def decorated(*args, **kwargs):
token = get_token_auth_header()
jsonurl = urlopen("https://"+AUTH0_DOMAIN+"/.well-known/jwks.json")
jwks = json.loads(jsonurl.read())
unverified_header = jwt.get_unverified_header(token)
rsa_key = {}
for key in jwks["keys"]:
if key["kid"] == unverified_header["kid"]:
rsa_key = {
"kty": key["kty"],
"kid": key["kid"],
"use": key["use"],
"n": key["n"],
"e": key["e"]
}
if rsa_key:
try:
payload = jwt.decode(
token,
rsa_key,
algorithms=ALGORITHMS,
audience=API_IDENTIFIER,
issuer="https://"+AUTH0_DOMAIN+"/"
)
except jwt.ExpiredSignatureError:
raise AuthError({"code": "token_expired",
"description": "token is expired"}, 401)
except jwt.JWTClaimsError:
raise AuthError({"code": "invalid_claims",
"description":
"incorrect claims,"
"please check the audience and issuer"}, 401)
except Exception:
raise AuthError({"code": "invalid_header",
"description":
"Unable to parse authentication"
" token."}, 401)
_request_ctx_stack.top.current_user = payload
return f(*args, **kwargs)
raise AuthError({"code": "invalid_header",
"description": "Unable to find appropriate key"}, 401)
return decorated
The newly created requires_auth
decorator, when applied to an endpoint, will automatically reject the request if no valid user can be authenticated.
We are ready to secure our endpoints, let’s update the user
and admin
endpoints to utilize our decorator.
@app.route("/user")
@requires_auth
def user_view():
"""
User endpoint, can only be accessed by an authorized user
"""
return jsonify(msg="Hello user!")
@app.route("/admin")
@requires_auth
def admin_view():
"""
Admin endpoint, can only be accessed by an admin
"""
return jsonify(msg="Hello admin!")
Our only change was adding @required_auth
at the top of the declaration of each endpoint function, and with that we can test once again:
~ curl -i http://localhost:5000/user
HTTP/1.0 401 UNAUTHORIZED
Content-Type: application/json
Content-Length: 89
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:42:26 GMT
{"code":"authorization_header_missing","description":"Authorization header is expected"}
~ curl -i http://localhost:5000/admin
HTTP/1.0 401 UNAUTHORIZED
Content-Type: application/json
Content-Length: 89
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:42:42 GMT
{"code":"authorization_header_missing","description":"Authorization header is expected"}
As expected, we can’t access our endpoints as the authorization header is missing. But before we add one, let’s see if our public endpoint still works:
~ curl -i http://localhost:5000
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:43:55 GMT
{"msg":"Hello world!"}
Awesome, it works as expected.
For testing our newly secured endpoints, we need to get a valid access token that we can pass to the request. We can do that directly on the Test
tab on the API details page, and it’s as simple as copying a value from the screen:
Copying the token for testing
Once we have the token we can change our curl request accordingly:
~ curl -i -H "Authorization: bearer [ACCESS_TOKEN]" http://localhost:5000/user
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 22
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 22:17:06 GMT
{"msg":"Hello user!"}
Please remember to replace [ACCESS_TOKEN]
with the value you copied from the dashboard.
It works! But we still have some work to do. Even though our /admin
endpoint is secured, it can be accessed by any user:
~ curl -i -H "Authorization: bearer [ACCESS_TOKEN]" http://localhost:5000/admin
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 22:21:09 GMT
{"msg":"Hello admin!"}
For role-based access control there’s a few things we need to do:
The first 2 points are very well explained in the Auth0 docs, so just make sure you add the corresponding permissions on your API.
Next, we need to update the code. We need a function to check if a given permission exists in the access token and return True
if it does and False
if it does not:
def requires_scope(required_scope):
"""
Determines if the required scope is present in the Access Token
Args:
required_scope (str): The scope required to access the resource
"""
token = get_token_auth_header()
unverified_claims = jwt.get_unverified_claims(token)
if unverified_claims.get("scope"):
token_scopes = unverified_claims["scope"].split()
for token_scope in token_scopes:
if token_scope == required_scope:
return True
return False
And lastly, it can be used as follows:
@app.route("/admin")
@requires_auth
def admin_view():
"""
Admin endpoint, can only be accessed by an admin
"""
if requires_scope("read:admin"):
return jsonify(msg="Hello admin!")
raise AuthError({
"code": "Unauthorized",
"description": "You don't have access to this resource"
}, 403)
Now, only users with the permission read:admin
can access our admin endpoint.
In order to test your final implementation, you can follow the steps detailed on obtaining an access token for a given user.
You can also use the Auth0 Dashboard to test permissions, but that is outside the scope of this article. If you would like to learn more about it, read here.
Today we learned how to secure a Flask API. We explored the do-it-yourself path, and we built a secure API with three levels of access – public access, private access and privately-scoped access.
There’s so much more that Auth0 can do for your APIs and also for your client applications. Today we just scratched the surface, and it’s up to you and your team when working with real-life scenarios to explore all the potential of their services.
The full code is available on GitHub.
Original article source at https://www.freecodecamp.org
#security #api #flask #auth0
1675502580
Auth0 SDK for signing in to your Next.js applications.
The Auth0 Next.js SDK is a library for implementing user authentication in Next.js applications.
Using npm:
npm install @auth0/nextjs-auth0
This library supports the following tooling versions:
>=10
Create a Regular Web Application in the Auth0 Dashboard.
If you're using an existing application, verify that you have configured the following settings in your Regular Web Application:
- Click on the "Settings" tab of your application's page.
- Scroll down and click on the "Show Advanced Settings" link.
- Under "Advanced Settings", click on the "OAuth" tab.
- Ensure that "JsonWebToken Signature Algorithm" is set to
RS256
and that "OIDC Conformant" is enabled.
Next, configure the following URLs for your application under the "Application URIs" section of the "Settings" page:
http://localhost:3000/api/auth/callback
http://localhost:3000/
Take note of the Client ID, Client Secret, and Domain values under the "Basic Information" section. You'll need these values in the next step.
You need to allow your Next.js application to communicate properly with Auth0. You can do so by creating a .env.local
file under your root project directory that defines the necessary Auth0 configuration values as follows:
# A long, secret value used to encrypt the session cookie
AUTH0_SECRET='LONG_RANDOM_VALUE'
# The base url of your application
AUTH0_BASE_URL='http://localhost:3000'
# The url of your Auth0 tenant domain
AUTH0_ISSUER_BASE_URL='https://YOUR_AUTH0_DOMAIN.auth0.com'
# Your Auth0 application's Client ID
AUTH0_CLIENT_ID='YOUR_AUTH0_CLIENT_ID'
# Your Auth0 application's Client Secret
AUTH0_CLIENT_SECRET='YOUR_AUTH0_CLIENT_SECRET'
You can execute the following command to generate a suitable string for the AUTH0_SECRET
value:
node -e "console.log(crypto.randomBytes(32).toString('hex'))"
You can see a full list of Auth0 configuration options in the "Configuration properties" section of the "Module config" document.
For more details about loading environment variables in Next.js, visit the "Environment Variables" document.
Go to your Next.js application and create a catch-all, dynamic API route handler under the /pages/api
directory:
Create an auth
directory under the /pages/api/
directory.
Create a [...auth0].js
file under the newly created auth
directory.
The path to your dynamic API route file would be /pages/api/auth/[...auth0].js
. Populate that file as follows:
import { handleAuth } from '@auth0/nextjs-auth0';
export default handleAuth();
Executing handleAuth()
creates the following route handlers under the hood that perform different parts of the authentication flow:
/api/auth/login
: Your Next.js application redirects users to your identity provider for them to log in (you can optionally pass a returnTo
parameter to return to a custom relative URL after login, for example /api/auth/login?returnTo=/profile
)./api/auth/callback
: Your identity provider redirects users to this route after they successfully log in./api/auth/logout
: Your Next.js application logs out the user./api/auth/me
: You can fetch user profile information in JSON format.Wrap your pages/_app.js
component with the UserProvider
component:
// pages/_app.js
import React from 'react';
import { UserProvider } from '@auth0/nextjs-auth0/client';
export default function App({ Component, pageProps }) {
return (
<UserProvider>
<Component {...pageProps} />
</UserProvider>
);
}
You can now determine if a user is authenticated by checking that the user
object returned by the useUser()
hook is defined. You can also log in or log out your users from the frontend layer of your Next.js application by redirecting them to the appropriate automatically-generated route:
// pages/index.js
import { useUser } from '@auth0/nextjs-auth0/client';
export default function Index() {
const { user, error, isLoading } = useUser();
if (isLoading) return <div>Loading...</div>;
if (error) return <div>{error.message}</div>;
if (user) {
return (
<div>
Welcome {user.name}! <a href="/api/auth/logout">Logout</a>
</div>
);
}
return <a href="/api/auth/login">Login</a>;
}
Next linting rules might suggest using the
Link
component instead of an anchor tag. TheLink
component is meant to perform client-side transitions between pages. As the links point to an API route and not to a page, you should keep them as anchor tags.
There are two additional ways to check for an authenticated user; one for Next.js pages using withPageAuthRequired and one for Next.js API routes using withAPIAuthRequired.
For other comprehensive examples, see the EXAMPLES.md document.
import * from @auth0/nextjs-auth0
import * from @auth0/nextjs-auth0/edge
import * from @auth0/nextjs-auth0/client
import * from @auth0/nextjs-auth0/testing
Visit the auto-generated API Docs for more details
All cookies will be set to HttpOnly, SameSite=Lax
and will be set to Secure
if the application's AUTH0_BASE_URL
is https
.
The HttpOnly
setting will make sure that client-side JavaScript is unable to access the cookie to reduce the attack surface of XSS attacks.
The SameSite=Lax
setting will help mitigate CSRF attacks. Learn more about SameSite by reading the "Upcoming Browser Behavior Changes: What Developers Need to Know" blog post.
Many hosting providers will offer to cache your content at the edge in order to serve data to your users as fast as possible. For example Vercel will cache your content on the Vercel Edge Network for all static content and Serverless Functions if you provide the necessary caching headers on your response.
It's generally a bad idea to cache any response that requires authentication, even if the response's content appears safe to cache there may be other data in the response that isn't.
This SDK offers a rolling session by default, which means that any response that reads the session will have a Set-Cookie
header to update the cookie's expiry. Vercel and potentially other hosting providers include the Set-Cookie
header in the cached response, so even if you think the response's content can be cached publicly, the responses Set-Cookie
header cannot.
Check your hosting provider's caching rules, but in general you should never cache responses that either require authentication or even touch the session to check authentication (eg when using withApiAuthRequired
, withPageAuthRequired
or even just getSession
or getAccessToken
).
Errors that come from Auth0 in the redirect_uri
callback may contain reflected user input via the OpenID Connect error
and error_description
query parameter. Because of this, we do some basic escaping on the message
, error
and error_description
properties of the IdentityProviderError
.
But, if you write your own error handler, you should not render the error message
, or error
and error_description
properties without using a templating engine that will properly escape them for other HTML contexts first.
With Next.js you can deploy a Next.js application under a sub-path of a domain using Base Path and serve internationalized (i18n) routes using Internationalized Routing.
If you use these features the urls of your application will change and so the urls to the nextjs-auth0 routes will change. To accommodate this there are various places in the SDK that you can customise the url.
For example, if basePath: '/foo'
you should prepend this to the loginUrl
and profileUrl
specified in your Auth0Provider
:
// _app.jsx
function App({ Component, pageProps }) {
return (
<UserProvider loginUrl="/foo/api/auth/login" profileUrl="/foo/api/auth/me">
<Component {...pageProps} />
</UserProvider>
);
}
Also, any links to login or logout should include the basePath
:
<a href="/foo/api/auth/login">Login</a><br />
<a href="/foo/api/auth/logout">Logout</a>
You should configure the baseUrl (or the AUTH0_BASE_URL
environment variable). For example:
# .env.local
AUTH0_BASE_URL=http://localhost:3000/foo
For any pages that are protected with the Server Side withPageAuthRequired you should update the returnTo
parameter depending on the basePath
and locale
if necessary.
// ./pages/my-ssr-page.jsx
export default MySsrPage = () => <></>;
const getFullReturnTo = (ctx) => {
// TODO: implement getFullReturnTo based on the ctx.resolvedUrl, ctx.locale
// and your next.config.js's basePath and i18n settings.
return '/foo/en-US/my-ssr-page';
};
export const getServerSideProps = (ctx) => {
const returnTo = getFullReturnTo(ctx.req);
return withPageAuthRequired({ returnTo })(ctx);
};
We also provide an Auth0 React SDK, auth0-react, which may be suitable for your Next.js application.
The SPA security model used by auth0-react
is different from the Web Application security model used by this SDK. In short, this SDK protects pages and API routes with a cookie session (see "Cookies and Security"). A SPA library like auth0-react
will store the user's ID token and access token directly in the browser and use them to access external APIs directly.
You should be aware of the security implications of both models. However, auth0-react may be more suitable for your needs if you meet any of the following scenarios:
By default, the SDK creates and manages a singleton instance to run for the lifetime of the application. When testing your application, you may need to reset this instance, so its state does not leak between tests.
If you're using Jest, we recommend using jest.resetModules()
after each test. Alternatively, you can look at creating your own instance of the SDK, so it can be recreated between tests.
For end to end tests, have a look at how we use a mock OIDC Provider.
Deploying
For deploying, have a look at how we deploy our example app to Vercel.
We appreciate feedback and contribution to this repo! Before you get started, please read the following:
Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.
Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?
Author: auth0
Source Code: https://github.com/auth0/nextjs-auth0
License: MIT license
1675240441
This tutorial will show how easy it is to call an Azure function after a user authenticates. Integrating Azure Functions Using Auth0 Actions. Calling custom Azure functions after users authenticate has never been easier!
Daniel Krzyczkowski is a member of our Auth0 by Okta Ambassador program. In this video, he will show how easy it is to call an Azure function after a user authenticates. We get to see everything from the Azure function code, how to get the URL for the function within the Azure dashboard, how to call that function within an Auth0 Action, how to add the Action to the login flow, and then he will demo it out for us. All of this in less than 10 minutes!
Learn more about the Auth0 by Okta Ambassador Program here - https://auth0.com/ambassador-program
#azure #auth0
1673419474
Chapters:
00:00 Intro
1:22 Running the Example Project
3:33 Dependency Injection System in FastAPI
5:09 Configuring an API in Auth0
7:10 Protecting the Endpoint
16:16 Making Protected Requests
24:54 Outro
Links:
- Code sample: https://github.com/jtemporal/fastapi-and-auth0
#api #fastapi #auth0
1661499566
Hey there! I'm Art, and this is my blog and website. I've built it myself with some inspiration from people I admire. I'm building it to learn new tech, sharpen my skills, and just generally to have fun :)
Next.js
powers the entire thingSanity.io
powers content and commentsAuth0
for user authMailgun
for email notificationsButtondown
powers the newsletterVercel
as hosting platformBetterStatus
for status monitoringFathom
for non-tracking, cookie-less analyticsJest
& Cypress
for unit and integration testsAuthor: rosnovsky
Source code: https://github.com/rosnovsky/rosnovsky.us
#nextjs #react #reactjs #auth0 #sanity
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
1659087600
Spring Boot OAuth 2.0 Client + MySQL
The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service.
An entity capable of granting access to a protected resource.
When the resource owner is a person, it is referred to as an end-user
.
> In other words , it's the end-user that accepts the authorization request.
An application
making protected resource requests on behalf of the
resource owner and with its authorization.
The server issuing access tokens
to the client after successfully
authenticating the resource owner and obtaining authorization.
> This access token will be used later to retrieve the protected resource.
The server hosting the protected resources, capable of _accepting
and responding_ to protected resource requests using access tokens.
In our example , we will be interested only to the client side of OAuth 2.
That is , registering the user in our mysql database after getting information from the OAuth2 Provider ( Google , Github)
> OAuth2 Client is our spring application.
> Resource Owner is the user.
> Authorization/Resource Server is the OAuth2 provider.
WebSecurityConfig
Extending the WebSecurityConfigurerAdapter class which , along with @EnableWebSecurity annotation , provides web based security and allows us to do some configurations like restricting some URL's for authentication , rejecting requests or maybe a defining a custom firwall .
AppController
Playing the role of a controller of requests in the MVC architecture thanks to Spring MVC.
We defined an endpoint "/user" to show the json data sent by the oauth provider after the login success.
User
and CustomOauth2User
The class User is our Model , in the MVC architecture , marked with @Entity JPA annotation to make the object ready for storage in the database.
The class CustomOauth2User will be used to get attributes of the data retrieved from the oauth provider.
UserRepository
Extending the JpaRepository class which makes database access very easy and allows us to perform creation , deletion , update and searching of users.
UserService
and CustomOauth2UserService
Classes that contains the @Service annotation and used to write business logic like finding a user by email or loading the user from the OauthProvider.
OAuth2LoginSuccessHandler
Extends the class SimpleUrlAuthenticationSuccessHandler which is used to specify any custom logic after the success of the authorization .
This class is needed to store the user in tha database after the login.
Create a new project and get a new pair of OAuth 2.0 clientId and clientSecret.
you'll need them for spring security oauth configuration in application.yaml
spring:
security:
oauth2:
client:
registration:
google:
clientId: PASTE_GOOGLE_CLIENT_ID_HERE
clientSecret: PASTE_GOOGLE_CLIENT_SECRET_HERE
scope:
- profile
- email
Scope are the information needed from the oauth provider .
In our case we need general profile information and also the email ( will be used later ) Also we need to set the URL callback to /oauth2/authorization/google
Using docker is not necessary here , you can use our local MySQL.
In our case we can use docker compose to create our database container.
docker-compose.yaml
:
version: "3.7"
services:
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: MYSQL_ROOT_PASSWORD
MYSQL_DATABASE: demo
Here we are using the version 3.7 of the docker compose . Then we are fetching the image of mysql version 8.0 from the Docker Registry. We also expose the port 3306 of the machine ( so we can access the container ) and the port 3306 of the container. Finally we set the root password and the name of the database that we want to create ( for example demo ).
Also we need to configue Spring JPA to use our mysql container.application.yaml
:
spring:
jpa:
hibernate:
ddl-auto: update
show-sql: true
datasource:
username: MYSQL_ROOT_USERNAME
password: MYSQL_ROOT_PASSWORD
url: jdbc:mysql://localhost:3306/demo
Last but not least , we run the command below to create the database instance.
$ cd spring-boot-oauth2-mysql
$ docker compose up
Let's demonstrate with our oauth 2.0 client implementation with some basic html template.
Before we proceed to the authorization server , let's show our current state of the database :
As we can see our user table is currently empty and our goal is to create a new user after the login success.
After clicking the link , we are redirected to a google page for authorization.
And we can hit the endpoint "/user" to take a peak about the data send to us by google.
And Boom , we obtained the full name and email address , that's exactly what we configured in the application.yaml
So now that we have the data we can actually display the name of the user , as well as registering him in the database .
Here we can see the user registered successfully thanks to the class OAuth2LoginSuccessHandler .
And also we updated to front page to show the name of current logged-in user.
Download details:
Author: salaheddine-zemmouri
Source code: https://github.com/salaheddine-zemmouri/Spring-Boot-OAuth-2.0-Client-MySQL
License:
#spring #java #springboot #auth0 #mysql
1658863800
J'ai récemment utilisé Auth0 dans un projet parallèle d'application à page unique (SPA), car je ne voulais pas passer du temps à créer toutes les fonctionnalités liées à l'authentification, par exemple la réinitialisation du mot de passe, l'inscription, etc. Étonnamment, il était extrêmement pénible de le faire fonctionner. localement en raison de problèmes HTTPS, CORS et localhost. Dans cet article de blog, je vais parcourir ma configuration finale avec tout cela en local.
Je vais pour une architecture d'application simple et très standard dans mon projet. Je voulais séparer mon frontend du backend parce que je ne voulais pas de Server Sider Rendering (SSR). Lorsque l'utilisateur visite mon application Web, je veux que le frontend appelle le backend pour toutes les données.
Dans ce cas, j'utilise React (create-react-app) sur le serveur frontend et Node express sur le backend.
Voici un diagramme mis à jour avec Auth0 ajouté à l'image. Maintenant, le flux est un peu plus complexe. Lorsque quelqu'un visite mon application Web, je souhaite maintenant le rediriger vers Auth0 pour s'inscrire ou se connecter avant de revenir à mon application pour poursuivre le parcours utilisateur (étapes 1, 2 et 3 du diagramme).
Lorsque l'utilisateur souhaite modifier des données d'application, le frontend attache le jeton du porteur d'Auth0 et l'envoie avec la demande au backend (étapes 4 à 5). Le backend vérifiera ensuite que l'utilisateur est bien celui qu'il prétend être en appelant Auth0 avec ce jeton de support, puis renverra les données au frontend si tout va bien (étapes 6 à 8). Enfin, le frontal affichera l'interface utilisateur mise à jour sur le navigateur (étape 9).
Ce flux est plus complexe que celui avec lequel nous avons commencé, mais il reste assez standard. Tout type de service d'authentification ou d'authentification unique (SSO) impliquera un processus similaire. Passons maintenant à la partie la plus complexe - la configuration locale.
Bien qu'Auth0 ait dédié une section Tester les applications localement sur son site Web qui se concentre sur les tests d'applications locales, malheureusement, c'est assez basique en ce qui concerne la documentation. Il est difficile de déterminer à quel type d'architecture d'application ils font référence. Autant que je sache, cette section semble concerner les applications SSR, pas SPA. Il y a aussi une section sur HTTPS dans le développement (j'expliquerai pourquoi nous avons besoin de HTTPS plus tard), ce qui, j'en suis certain, n'est pas pour l'architecture de notre diagramme ci-dessus.
Bref, je n'ai pas trouvé de bons conseils sur le site Web d'Auth0, j'ai donc dû créer le mien.
Nous ne pouvons pas nous authentifier avec Auth0 si notre frontend fonctionne en mode HTTP. Si vous le faites, vous obtiendrez le message d'erreur suivant.
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.
Heureusement, il est assez facile de contourner ce problème si vous utilisez créer une application de réaction, c'est aussi simple que HTTPS=true
votre commande de démarrage, par exemple HTTPS=true npm start
. En savoir plus ici .
Cela résout le problème avec Auth0, mais maintenant Chrome se plaindra que notre interface HTTPS envoie maintenant des requêtes non sécurisées (HTTP) au backend. Nous devrons donc ensuite exécuter le backend en mode HTTPS. Pour ce faire avec Express, nous aurons besoin de générer des certificats, je recommande d'utiliser mkcert . Cela produira deux fichiers, une clé et un certificat, dont nous aurons tous deux besoin pour exécuter le serveur Express en mode HTTPS. Vous ferez alors quelque chose comme ce qui suit.
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");
Eh bien, maintenant que nous avons ces certificats, autant les utiliser sur le frontend. Créez à nouveau une application de réaction à la rescousse ! Tout ce que nous avons à faire est d'inclure les éléments suivants dans notre .env
fichier et de react-scripts
les récupérer automatiquement pendant le mode de développement.
SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem
Pour effectuer l'étape 5 du deuxième diagramme, nous devons utiliser getAccessTokenSilently()
(encore une fois, j'utilise React, votre kilométrage peut varier) pour extraire le jeton du porteur que nous devons transmettre à notre backend. Ceci, cependant, déclenchera une vérification du consentement (même s'il s'agit d'une application propriétaire !) et si nous l'exécutons, [localhost](http://localhost)
il échouera silencieusement. Vous pouvez en savoir plus à ce sujet sur la page Consentement de l'utilisateur et applications tierces .
Si vous êtes sur Mac ou Linux, éditez /etc/host
, si vous êtes Windows, c'est le cas C:\Windows\System32\Drivers\etc\hosts
. Vous pouvez remplacer [localhost](http://localhost)
par [example.site](http://example.site)
mais je préfère garder les deux puisque je travaille sur des bases de code qui supposent localhost
aussi.
127.0.0.1 localhost example.site
CORS sur l'environnement local est tellement frustrant. Si vous suivez les instructions ci-dessus, nous espérons que dans votre serveur Express, vous pourrez simplement ajouter ce qui suit et tout devrait fonctionner.
import cors from "cors";
...
app.use(cors());
Vous pouvez également envisager d'ajouter une logique de liste blanche.
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));
Si cela ne fonctionne toujours pas, essayez d'autoriser n'importe quelle origine. Bien sûr, ce n'est pas sûr, alors revenez-y plus tard et protégez-le pour la production.
import cors from "cors";
...
const corsOptions = {
origin: '*',
};
...
app.use(cors(corsOptions));
...
Si vous envisagez d'utiliser Auth0, je suis tombé sur un autre service appelé Magic qui semble offrir une bien meilleure expérience de développement dans son ensemble. La configuration de leur environnement local semble trop belle pour être vraie, consultez-la ici . Cependant, la raison pour laquelle j'ai opté pour Auth0 à la fin est à cause de leur niveau gratuit généreux qui permet jusqu'à 1000 utilisateurs actifs. Magic in compare les frais en fonction du nombre de connexions d'utilisateurs et il n'y a pas d'allocation gratuite.
1658860200
Eu usei Auth0 em um projeto paralelo de Single Page Application (SPA) recentemente, porque eu não queria gastar tempo para construir todos os recursos relacionados à autenticação, por exemplo, redefinição de senha, inscrição, etc. Surpreendentemente, foi extremamente doloroso fazê-lo funcionar localmente devido a problemas de HTTPS, CORS e localhost. Nesta postagem do blog, estarei acompanhando minha configuração final com tudo isso funcionando localmente.
Eu estou indo para uma arquitetura de aplicativo simples e muito padrão no meu projeto. Eu queria separar meu front-end do back-end porque não queria Server Sider Rendering (SSR). Quando o usuário visita meu aplicativo da Web, quero que o front-end chame o back-end para quaisquer dados.
Nesse caso, estou usando o React (create-react-app) no frontend e o servidor Node express no backend.
Aqui está um diagrama atualizado com Auth0 adicionado à imagem. Agora o fluxo é um pouco mais complexo. Quando alguém visita meu aplicativo Web, agora quero redirecioná-lo para Auth0 para se inscrever ou entrar antes de retornar ao meu aplicativo para continuar com a jornada do usuário (etapas 1, 2 e 3 no diagrama).
Quando o usuário quiser editar qualquer dado do aplicativo, o front-end anexará o token do portador de Auth0 e o enviará com a solicitação ao back-end (etapas 4 a 5). O back-end irá então verificar se o usuário é quem eles alegam ser chamando Auth0 com esse token de portador e, em seguida, retornar os dados ao front-end se tudo estiver correto (etapas 6 a 8). Por fim, o front end exibirá a UI atualizada no navegador (etapa 9).
Esse fluxo é mais complexo em comparação com o que começamos, mas ainda é bastante padrão. Qualquer tipo de serviço de autenticação ou Single Sign On (SSO) envolverá um processo semelhante. Agora vamos para a parte mais complexa - configuração local.
Embora o Auth0 tenha dedicado uma seção Test Applications Locally em seu site que se concentra no teste de aplicativos locais, infelizmente, é bastante básico no que diz respeito à documentação. É difícil identificar a que tipo de arquitetura de aplicativo eles estão se referindo. Tanto quanto eu entendo, esta seção parece ser para aplicativos SSR, não SPA. Há também uma seção sobre HTTPS em desenvolvimento (explicarei por que precisamos de HTTPS mais tarde), que tenho certeza que não é para a arquitetura em nosso diagrama acima.
Para encurtar a história, não encontrei nenhuma boa orientação no site da Auth0, então tive que forjar o meu.
Não podemos autenticar com Auth0 se nosso frontend estiver sendo executado no modo HTTP. Se fizer isso, você receberá a seguinte mensagem de erro.
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.
Felizmente, é muito fácil contornar isso se você estiver usando o aplicativo create react, é tão simples quanto HTTPS=true
o seu comando start, por exemplo HTTPS=true npm start
. Veja mais sobre isso aqui .
Isso corrige o problema com Auth0, mas agora o Chrome reclamará que nosso front-end HTTPS está enviando solicitações não seguras (HTTP) para o back-end. Então, em seguida, precisaremos executar o backend no modo HTTPS. Para fazer isso com o Express, precisaremos gerar alguns certificados, recomendo usar mkcert . Isso produzirá dois arquivos, uma chave e um certificado, que ambos precisaremos para executar o servidor Express no modo HTTPS. Você então fará algo como o seguinte.
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");
Bem, agora que temos esses certificados, podemos usá-los no frontend. Crie um aplicativo de reação para o resgate novamente! Tudo o que precisamos fazer é incluir o seguinte em nosso .env
arquivo e react-scripts
buscá-lo durante o modo de desenvolvimento automaticamente.
SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem
Para fazer o passo 5 no segundo diagrama, precisamos usar getAccessTokenSilently()
(novamente estou usando React, sua milhagem pode variar) para extrair o token do portador que precisamos passar para nosso backend. Isso, no entanto, acionará uma verificação de consentimento (mesmo que seja um aplicativo primário!) e, se estivermos executando, [localhost](http://localhost)
ele falhará silenciosamente. Você pode ler mais sobre isso na página de consentimento do usuário e aplicativos de terceiros .
Se você estiver no mac ou linux, edite /etc/host
, se você for windows, é C:\Windows\System32\Drivers\etc\hosts
. Você poderia substituir [localhost](http://localhost)
por [example.site](http://example.site)
, mas prefiro manter os dois, pois trabalho em bases de código que localhost
também assumem.
127.0.0.1 localhost example.site
CORS no ambiente local é tão frustrante. Se você seguir as instruções acima, espero que no seu servidor Express você possa adicionar o seguinte e tudo deve funcionar.
import cors from "cors";
...
app.use(cors());
Como alternativa, considere adicionar alguma lógica de lista de permissões.
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));
Se ainda não funcionar, tente permitir qualquer origem. Claro, isso não é seguro, então volte a isso mais tarde e à prova de balas para produção.
import cors from "cors";
...
const corsOptions = {
origin: '*',
};
...
app.use(cors(corsOptions));
...
Se você está pensando em usar Auth0, me deparei com outro serviço chamado Magic que parece oferecer uma experiência de desenvolvimento muito melhor como um todo. A configuração do ambiente local deles parece boa demais para ser verdade, confira aqui . No entanto, a razão pela qual fui com Auth0 no final é por causa de seu generoso nível gratuito, que permite até 1.000 usuários ativos. Magic em taxas de comparação com base no número de logins de usuários e não há subsídio gratuito.
1658860200
Utilicé Auth0 en un proyecto paralelo de una aplicación de página única (SPA) recientemente, porque no quería perder el tiempo para crear todas las funciones relacionadas con la autenticación, por ejemplo, restablecimiento de contraseña, registro, etc. Sorprendentemente, fue extremadamente doloroso hacerlo funcionar. localmente debido a problemas de HTTPS, CORS y localhost. En esta publicación de blog, mostraré mi configuración final con todo eso trabajando localmente.
Estoy buscando una arquitectura de aplicaciones simple y muy estándar en mi proyecto. Quería separar mi frontend del backend porque no quería Server Side Rendering (SSR). Cuando el usuario visita mi aplicación web, quiero que el frontend llame al backend para obtener cualquier información.
En este caso, estoy usando React (create-react-app) en el frontend y el servidor Node express en el backend.
Aquí hay un diagrama actualizado con Auth0 agregado a la imagen. Ahora el flujo es un poco más complejo. Cuando alguien visita mi aplicación web, ahora quiero redirigirlo a Auth0 para registrarse o iniciar sesión antes de regresar a mi aplicación para continuar con el recorrido del usuario (pasos 1, 2 y 3 en el diagrama).
Cuando el usuario quiera editar los datos de la aplicación, la interfaz adjuntará el token de portador de Auth0 y lo enviará con la solicitud al backend (pasos 4 y 5). Luego, el backend verificará que el usuario es quien dice ser llamando a Auth0 con ese token de portador, luego devolverá los datos al frontend si todo está bien (pasos 6 a 8). Finalmente, la interfaz mostrará la interfaz de usuario actualizada en el navegador (paso 9).
Este flujo es más complejo en comparación con lo que comenzamos, pero sigue siendo bastante estándar. Cualquier tipo de servicio de autenticación o inicio de sesión único (SSO) implicará un proceso similar. Ahora pasemos a la parte más compleja: la configuración local.
Si bien Auth0 ha dedicado una sección de Prueba de aplicaciones localmente en su sitio web que se enfoca en la prueba de aplicaciones locales, desafortunadamente, es bastante básica en lo que respecta a la documentación. Es difícil determinar a qué tipo de arquitectura de aplicaciones se refieren. Según tengo entendido, esta sección parece ser para aplicaciones SSR, no para SPA. También hay una sección sobre HTTPS en desarrollo (explicaré por qué necesitamos HTTPS más adelante), que estoy seguro no es para la arquitectura de nuestro diagrama anterior.
En pocas palabras, no encontré ninguna buena guía en el sitio web de Auth0, así que tuve que forjar la mía.
No podemos autenticarnos con Auth0 si nuestra interfaz se ejecuta en modo HTTP. Si lo hace, recibirá el siguiente mensaje de error.
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.
Afortunadamente, es bastante fácil evitar esto si está utilizando la aplicación Create React, es tan simple como HTTPS=true
su comando de inicio, por ejemplo HTTPS=true npm start
. Vea más sobre esto aquí .
Hacer esto soluciona el problema con Auth0, pero ahora Chrome se quejará de que nuestro frontend HTTPS ahora está enviando solicitudes no seguras (HTTP) al backend. Entonces, a continuación, necesitaremos ejecutar el backend en modo HTTPS. Para hacer esto con Express, necesitaremos generar algunos certificados, recomiendo usar mkcert . Esto generará dos archivos, una clave y un certificado, que ambos necesitaremos para ejecutar el servidor Express en modo HTTPS. A continuación, hará algo como lo siguiente.
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");
Bueno, ahora que tenemos estos certificados, también podríamos usarlos en la interfaz. ¡Crea una aplicación de reacción al rescate de nuevo! Todo lo que tenemos que hacer es incluir lo siguiente en nuestro .env
archivo y react-scripts
lo recogerá automáticamente durante el modo de desarrollo.
SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem
Para realizar el paso 5 en el segundo diagrama, necesitamos usar getAccessTokenSilently()
(nuevamente estoy usando React, su kilometraje puede variar) para extraer el token de portador que necesitamos pasar a nuestro backend. Sin embargo, esto activará una verificación de consentimiento (¡aunque se trata de una aplicación propia!) y, si la estamos ejecutando [localhost](http://localhost)
, fallará en silencio. Puede obtener más información al respecto en la página Consentimiento del usuario y aplicaciones de terceros .
Si está en Mac o Linux, edite /etc/host
, si está en Windows, es C:\Windows\System32\Drivers\etc\hosts
. Puede reemplazar [localhost](http://localhost)
con [example.site](http://example.site)
pero prefiero mantener ambos ya que trabajo en bases de código que localhost
también asumen.
127.0.0.1 localhost example.site
CORS en el entorno local es muy frustrante. Si sigue las instrucciones anteriores, es de esperar que en su servidor Express pueda agregar lo siguiente y todo debería funcionar.
import cors from "cors";
...
app.use(cors());
Alternativamente, considere agregar alguna lógica de lista blanca.
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));
Si sigue sin funcionar, prueba a permitir cualquier origen. Por supuesto, esto no es seguro, así que vuelva a esto más tarde y pruébelo para la producción.
import cors from "cors";
...
const corsOptions = {
origin: '*',
};
...
app.use(cors(corsOptions));
...
Si está pensando en usar Auth0, encontré otro servicio llamado Magic que parece ofrecer una experiencia de desarrollo mucho mejor en general. La configuración de su entorno local parece demasiado buena para ser verdad, échale un vistazo aquí . Sin embargo, la razón por la que opté por Auth0 al final es por su generoso nivel gratuito que permite hasta 1000 usuarios activos. La magia en los cargos de comparación se basa en la cantidad de inicios de sesión de los usuarios y no hay una asignación gratuita.
1658858880
Gần đây, tôi đã sử dụng Auth0 trong một dự án bên Ứng dụng trang đơn (SPA), vì tôi không muốn dành thời gian để xây dựng tất cả các tính năng liên quan đến xác thực, ví dụ như đặt lại mật khẩu, đăng ký, v.v. Đáng ngạc nhiên là rất khó để làm cho nó hoạt động cục bộ do sự cố HTTPS, CORS và máy chủ cục bộ. Trong bài đăng trên blog này, tôi sẽ hướng dẫn thiết lập cuối cùng của mình với tất cả những thứ đó hoạt động cục bộ.
Tôi sẽ tìm kiếm kiến trúc ứng dụng đơn giản và rất chuẩn trong dự án của mình. Tôi muốn tách giao diện người dùng của mình khỏi phần phụ trợ vì tôi không muốn Hiển thị Máy chủ (SSR). Khi người dùng truy cập ứng dụng web của tôi, tôi muốn giao diện người dùng gọi phần phụ trợ cho bất kỳ dữ liệu nào.
Trong trường hợp này, tôi đang sử dụng React (create-react-app) trên frontend và Node express server trên backend.
Đây là sơ đồ được cập nhật với Auth0 được thêm vào hình ảnh. Bây giờ dòng chảy phức tạp hơn một chút. Khi ai đó truy cập ứng dụng web của tôi, bây giờ tôi muốn chuyển hướng họ đến Auth0 để đăng ký hoặc đăng nhập trước khi quay lại ứng dụng của tôi để tiếp tục hành trình của người dùng (bước 1, 2 và 3 trong sơ đồ).
Khi người dùng muốn chỉnh sửa bất kỳ dữ liệu ứng dụng nào, giao diện người dùng sẽ đính kèm mã thông báo mang từ Auth0 và gửi nó cùng với yêu cầu đến phụ trợ (bước 4 - 5). Sau đó, chương trình phụ trợ sẽ xác minh người dùng là người mà họ tuyên bố bằng cách gọi Auth0 với mã thông báo mang tên đó, sau đó trả lại dữ liệu cho giao diện người dùng nếu tất cả đều tốt (bước 6 - 8). Cuối cùng, giao diện người dùng sẽ hiển thị giao diện người dùng được cập nhật trên trình duyệt (bước 9).
Luồng này phức tạp hơn so với những gì chúng ta đã bắt đầu, nhưng nó vẫn khá chuẩn. Bất kỳ loại dịch vụ xác thực nào hoặc Đăng nhập một lần (SSO) sẽ liên quan đến một quy trình tương tự. Bây giờ đến phần phức tạp hơn - thiết lập cục bộ.
Mặc dù Auth0 đã dành riêng phần Kiểm tra ứng dụng cục bộ trong trang web của họ tập trung vào kiểm tra ứng dụng cục bộ, nhưng thật không may, nó khá cơ bản theo như tài liệu hướng dẫn. Thật khó để xác định loại kiến trúc ứng dụng mà họ đang đề cập đến. Theo như tôi hiểu, phần này dường như dành cho các ứng dụng SSR, không phải SPA. Ngoài ra còn có một phần về HTTPS trong Phát triển (tôi sẽ giải thích lý do tại sao chúng ta cần HTTPS sau), mà tôi chắc chắn không dành cho kiến trúc trong sơ đồ của chúng tôi ở trên.
Câu chuyện dài quá ngắn, tôi không tìm thấy bất kỳ hướng dẫn tốt nào trên trang web của Auth0 nên tôi phải tự học.
Chúng tôi không thể xác thực bằng Auth0 nếu giao diện người dùng của chúng tôi đang chạy ở chế độ HTTP. Nếu bạn làm vậy, bạn sẽ nhận được thông báo lỗi sau.
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.
May mắn thay, nó là khá dễ dàng để giải quyết vấn đề này nếu bạn đang sử dụng ứng dụng tạo phản ứng, nó đơn giản như HTTPS=true
lệnh bắt đầu của bạn, ví dụ HTTPS=true npm start
. Xem thêm về nó ở đây .
Việc làm này sẽ khắc phục được sự cố với Auth0, nhưng giờ đây Chrome sẽ phàn nàn rằng giao diện người dùng HTTPS của chúng tôi hiện đang gửi các yêu cầu không an toàn (HTTP) đến phần phụ trợ. Vì vậy, tiếp theo chúng ta sẽ cần chạy chương trình phụ trợ ở chế độ HTTPS. Để làm điều này với Express, chúng tôi sẽ cần tạo một số chứng chỉ, tôi khuyên bạn nên sử dụng mkcert . Thao tác này sẽ xuất ra hai tệp là khóa và chứng chỉ, cả hai tệp này chúng ta sẽ cần để chạy máy chủ Express ở chế độ HTTPS. Sau đó bạn sẽ làm như sau.
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");
Vâng, bây giờ chúng tôi có những chứng chỉ này, chúng tôi cũng có thể sử dụng chúng trên giao diện người dùng. Tạo ứng dụng phản ứng để giải cứu một lần nữa! Tất cả những gì chúng ta cần làm là đưa nội dung sau vào .env
tệp của mình và react-scripts
sẽ tự động chọn nó trong chế độ phát triển.
SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem
Để thực hiện bước 5 trong sơ đồ thứ hai, chúng ta cần sử dụng getAccessTokenSilently()
(một lần nữa tôi đang sử dụng React, số dặm của bạn có thể thay đổi) để trích xuất mã thông báo mang mà chúng ta cần chuyển cho chương trình phụ trợ của mình. Tuy nhiên, điều này sẽ kích hoạt kiểm tra sự đồng ý (ngay cả khi đây là ứng dụng của bên thứ nhất!) Và nếu chúng tôi đang chạy trên ứng dụng [localhost](http://localhost)
đó sẽ không thành công. Bạn có thể đọc thêm về nó trên trang Sự đồng ý của người dùng và Ứng dụng của bên thứ ba .
Nếu bạn đang sử dụng mac hoặc linux thì hãy chỉnh sửa /etc/host
, nếu bạn là windows thì chỉnh sửa C:\Windows\System32\Drivers\etc\hosts
. Bạn có thể thay thế [localhost](http://localhost)
bằng [example.site](http://example.site)
nhưng tôi muốn giữ lại cả hai vì tôi cũng làm việc trên các cơ sở mã giả định localhost
.
127.0.0.1 localhost example.site
CORS về môi trường địa phương thật đáng thất vọng. Nếu bạn làm theo các hướng dẫn ở trên, thì hy vọng trong máy chủ Express của mình, bạn có thể thêm những thứ sau và mọi thứ sẽ hoạt động.
import cors from "cors";
...
app.use(cors());
Ngoài ra, hãy xem xét thêm một số logic danh sách trắng.
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));
Nếu nó vẫn không hoạt động, hãy thử cho phép bất kỳ nguồn gốc nào. Tất nhiên, điều này không an toàn, vì vậy hãy quay lại điều này sau và chống đạn cho nó để sản xuất.
import cors from "cors";
...
const corsOptions = {
origin: '*',
};
...
app.use(cors(corsOptions));
...
Nếu bạn đang nghĩ đến việc sử dụng Auth0, tôi đã tìm thấy một dịch vụ khác có tên là Magic , dường như cung cấp toàn bộ trải nghiệm dành cho nhà phát triển tốt hơn nhiều. Thiết lập môi trường cục bộ của họ dường như quá tốt để trở thành sự thật, hãy kiểm tra tại đây . Tuy nhiên, lý do cuối cùng tôi đã sử dụng Auth0 là vì cấp độ miễn phí hào phóng của họ cho phép lên đến 1000 người dùng đang hoạt động. Magic trong so sánh tính phí dựa trên số lần đăng nhập của người dùng và không có phụ cấp miễn phí.
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 根据用户登录次数收费,并且没有免费限额。
1658855040
最近、シングルページアプリケーション(SPA)サイドプロジェクトでAuth0を使用しました。これは、パスワードのリセットやサインアップなど、認証に関連するすべての機能を構築するために時間を費やしたくなかったためです。驚くべきことに、Auth0を機能させるのは非常に苦痛でした。 HTTPS、CORS、およびlocalhostの問題が原因でローカルに発生します。このブログ投稿では、すべてがローカルで機能するように、最終的なセットアップについて説明します。
プロジェクトでは、シンプルで非常に標準的なアプリアーキテクチャを採用します。サーバーサイダーレンダリング(SSR)が必要なかったため、フロントエンドをバックエンドから分離したかったのです。ユーザーが私のWebアプリにアクセスしたときに、フロントエンドがデータのバックエンドを呼び出すようにします。
この場合、フロントエンドでReact(create-react-app)を使用し、バックエンドでNodeExpressサーバーを使用しています。
これは、Auth0が画像に追加された更新された図です。これで、フローはもう少し複雑になります。誰かが私のWebアプリにアクセスしたときに、サインアップまたはサインインするためにAuth0にリダイレクトしてから、アプリに戻ってユーザージャーニーを続行したいと思います(図のステップ1、2、3)。
ユーザーがアプリデータを編集する場合、フロントエンドはAuth0からベアラートークンを添付し、リクエストとともにバックエンドに送信します(ステップ4〜5)。次に、バックエンドは、そのベアラトークンを使用してAuth0を呼び出すことにより、ユーザーが本人であると主張していることを確認し、問題がなければデータをフロントエンドに返します(手順6〜8)。最後に、フロントエンドは更新されたUIをブラウザーに表示します(ステップ9)。
このフローは、私たちが始めたものと比較してより複雑ですが、それでもかなり標準的です。あらゆる種類の認証サービスまたはシングルサインオン(SSO)には、同様のプロセスが含まれます。次に、より複雑な部分であるローカルセットアップに移ります。
Auth0は、ローカルアプリのテストに焦点を当てたWebサイトのTest Applications Locallyセクションを用意していますが、残念ながら、ドキュメントに関する限り、これはかなり基本的なものです。参照しているアプリアーキテクチャのタイプを特定するのは困難です。私が理解している限り、このセクションはSPAではなくSSRアプリ向けのようです。開発中のHTTPSに関するセクションもあります(HTTPSが必要な理由については後で説明します)。これは、上の図のアーキテクチャには当てはまらないと確信しています。
非常に長い話ですが、Auth0のWebサイトで適切なガイダンスが見つからなかったため、自分で作成する必要がありました。
フロントエンドが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アプリを使用している場合は、これを回避するのは非常に簡単です。HTTPS=true
たとえば、startコマンドと同じくらい簡単HTTPS=true npm start
です。詳しくはこちらをご覧ください。
これを行うとAuth0の問題が修正されますが、ChromeはHTTPSフロントエンドがバックエンドに非セキュアリクエスト(HTTP)を送信していると文句を言います。したがって、次に、バックエンドをHTTPSモードで実行する必要があります。Expressでこれを行うには、いくつかの証明書を生成する必要があります。mkcertを使用することをお勧めします。これにより、キーと証明書の2つのファイルが出力されます。どちらも、ExpressサーバーをHTTPSモードで実行する必要があります。次に、次のようなことを行います。
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
2番目の図のステップ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人のアクティブユーザーを許可する寛大な無料利用枠のためです。マジックの比較料金はユーザーログイン数に基づいており、無料の手当はありません。
1658826785
I used Auth0 in a Single Page Application (SPA) side project recently, because I didn't want to spend the time to build all the auth related features e.g. password reset, sign up, etc. Surprisingly it was extremely painful to get it working locally due to HTTPS, CORS and localhost issues. In this blog post, I'll be walking my final setup with all of that working locally.
I am going for simple and very standard app architecture in my project. I wanted to separate my frontend from the backend because I didn't want Server Sider Rendering (SSR). When the user visits my web app, I want the frontend to call the backend for any data.
See more at: https://blog.hao.dev/how-to-setup-single-page-applications-with-auth0-in-local-environment-without-cors-issues