Alfie Mellor

Alfie Mellor

1679017587

React User Authentication with Auth0

Learn how to secure a React application by implementing user authentication with Auth0. A complete guide to React User Authentication with Auth0

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 

React User Authentication with Auth0
Callum Slater

Callum Slater

1675928668

How to Secure a Flask API with Auth0

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:

  1. Do it yourself approach
  2. Work with a safe 3rd party like Auth0

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.

Why Not Build Your Own Authentication and Authorization?

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:

  • Sprint 0: Research ideas and start prototyping
  • Sprint 1: Build user table and login screen with API
  • Sprint 2: Add password reset screens and build all email templates
  • Sprint 3: Build, create and list ToDos screens
  • Sprint 4: MVP goes live
  • User feedback:
    • Some users can’t log in due to a bug
    • Some users feel unsafe without 2-factor authentication
    • Some users don’t want to get yet another password. They prefer single sign-on with Google or Facebook.

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.

How to Set Up a Free Auth0 Identity Management Account

Auth0 is a leading authentication and authorization provider, but let’s see how it can help Bob (or you) build a better app:

  1. It saves time
  2. It’s secure
  3. It has a free plan

Time to get practical. First, make sure you have an Auth0 account. If not, you can create one here for free.

Create a New Auth0 API

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:

XccGez21ClEDsCECuKwiF_1AF5gj2OXXaJKEXVUOBFmxQ7Ci11a1g1O3cu_io185YbdnSJkAlu3dmP0pt6Ww-N6cPqQLTIeweSi2hNv4ototIkuSZhfiprjqcMrFhcMLaGkKfedkm8D0PR2IcjdLPGUChKS27wsiPMvqCsysQRJyGANVYc5Q5EbFdaFo

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.

How to Bootstrap our Application

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.

Install the dependencies

First, install the following dependencies for setting up Flask and authenticating users.

pipenv install flask python-dotenv python-jose flask-cors six

Build the endpoints

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!"}

How to Secure the Endpoints

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.

Auth0 configuration variables

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:

UffKcasZXNZmXldeB8nhDEjzmOPVao3PR6EUVPbtWzXStuDzcCw2kr5ztEnr0VlWCkBLbhleAM-D11Cv5Cv8fcII8m24D6TfEe4XfxWe8HXN1aNrF-dHeN05zeVeoNfQISWh-VPf0__x8uVfJPL3GGHYIC87utfrr6734Z9Wdk-9eJUApslcdUKOyoSh

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 /).

cA63NdLr4AWOz2O3jTWBXTTqc7DrGOr1aPOIpNDRYl97-o84I_lX8KtotCm6hRWF06ai0RjiJzgTjS_zRlySKFAB-XO1w737N05i7-bC2-GZioOpcWuS5gaRoEnDL63gXnm5CyP6JOEQusRLQMF1sY_1vjfXtdMVIr5uCW1PMIpokH76lpMq2VFZSIyf

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"]

Error methods

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

How to capture the JWT token

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

How to validate the 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.

How to require an authenticated request for an endpoint

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.

How to test it out

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:
 

XCAWL5taQUs3_5qcAdukl9FP_aTVLya-jyS_4IivFW6JCAfX5d2hbPPCIV4PB8QgcuceQrzC__YYpWMQB1y8HT9AnKO01XH5rCiofvQJAmiAPnGF42FcJFxaVHTLLQcL9UpzFjYgan0Qasna69DlZ8AIkoATbqAtqtqibWUszhvakHZiytPNduTU7_Hb

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!"}

Role-based access control

For role-based access control there’s a few things we need to do:

  1. Create permissions for the API
  2. Enable adding permissions to the JWT for the API
  3. Update the code
  4. Test with users

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.

Conclusion

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

How to Secure a Flask API with Auth0
Lawrence  Lesch

Lawrence Lesch

1675502580

Nextjs-auth0: Next.js SDK for Signing in with Auth0

Nextjs-auth0

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.

Getting Started

Installation

Using npm:

npm install @auth0/nextjs-auth0

This library supports the following tooling versions:

  • Node.js: 12 LTS and newer LTS releases are supported.
  • Next.js: >=10

Auth0 Configuration

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:

  • Allowed Callback URLs: http://localhost:3000/api/auth/callback
  • Allowed Logout URLs: 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.

Basic Setup

Configure the Application

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.

Add the Dynamic API Route

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.

Add the UserProvider to Custom App

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>
  );
}

Consume Authentication

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. The Link 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.

API Reference

Server (for Node.js)

import * from @auth0/nextjs-auth0

Edge (for Middleware and the Edge runtime)

import * from @auth0/nextjs-auth0/edge

Client (for the Browser)

import * from @auth0/nextjs-auth0/client

Testing helpers

import * from @auth0/nextjs-auth0/testing

Visit the auto-generated API Docs for more details

Cookies and Security

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.

Caching and Security

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).

Error Handling and Security

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.

Base Path and Internationalized Routing

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);
};

Comparison with the Auth0 React SDK

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:

  • You are using Static HTML Export with Next.js.
  • You do not need to access user data during server-side rendering.
  • You want to get the access token and call external API's directly from the frontend layer rather than using Next.js API routes as a proxy to call external APIs.

Testing

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.

Contributing

We appreciate feedback and contribution to this repo! Before you get started, please read the following:

Vulnerability Reporting

Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.

What is Auth0?

Auth0 Logo

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

Documentation

  • QuickStart- our guide for adding Auth0 to your Next.js app.
  • FAQs - Frequently asked questions about nextjs-auth0.
  • Examples - lots of examples for your different use cases.
  • Security - Some important security notices that you should check.
  • Architecture - Architectural overview of the SDK.
  • Testing - Some help with testing your nextjs-auth0 application.
  • Deploying - How we deploy our example app to Vercel.
  • Docs Site - explore our docs site and learn more about Auth0.

Download Details:

Author: auth0
Source Code: https://github.com/auth0/nextjs-auth0 
License: MIT license

#typescript #react #nextjs #auth0 

Nextjs-auth0: Next.js SDK for Signing in with Auth0

How to Call an Azure Function after a User Authenticates

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!

Integrating Azure Functions Using Auth0 Actions

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 

How to Call an Azure Function after a User Authenticates

How to Protect an API in FastAPI with Auth0

Learn how to protect an API in FastAPI with Auth0. Learn how to leverage the FastAPI dependency injection system to integrate your API with Auth0 and protect your endpoints. You'll see how that affects your API documentation and how you can use code we provided to verify your Auth0 access token

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

How to Protect an API in FastAPI with Auth0

Build Rosnovsky.us Site and Blog with Next.js, Auth0, and Sanity.io

What is this?

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 :)

What is this, really?

  • Next.js powers the entire thing
  • Sanity.io powers content and comments
  • Auth0 for user auth
  • Mailgun for email notifications
  • Buttondown powers the newsletter
  • Vercel as hosting platform
  • BetterStatus for status monitoring
  • Fathom for non-tracking, cookie-less analytics
  • Jest & Cypress for unit and integration tests
  • Apple Music for the widget below

More to come!

Download details:

Author: rosnovsky
Source code: https://github.com/rosnovsky/rosnovsky.us 

#nextjs #react #reactjs #auth0 #sanity 

Build Rosnovsky.us Site and Blog with Next.js, Auth0, and Sanity.io
Nat  Grady

Nat Grady

1661330940

Auth0: Authentication in Shinyapps using Auth0 Service

auth0

The goal of {auth0} is to implement an authentication scheme to Shiny using OAuth Apps through the freemium service Auth0.

Installation

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")

Tutorial

To create your authenticated shiny app, you need to follow the five steps below.

Step 1: Create an Auth0 account

  • Go to auth0.com
  • Click "Sign Up"
  • You can create an account with a user name and password combination, or by signing up with your GitHub or Google accounts.

Step 2: Create an Auth0 application

After logging into Auth0, you will see a page like this:

  • Click on "+ Create Application"
  • Give a name to your app
  • Select "Regular Web Applications" and click "Create"

Step 3: Configure your application

  • Go to the Settings in your selected application. You should see a page like this:

  • Add http://localhost:8080 to the "Allowed Callback URLs", "Allowed Web Origins" and "Allowed Logout URLs".
    • You can change http://localhost:8080 to another port.
  • Add the remote server where you are going to deploy your shiny app to the same boxes.
    • Just make sure that these addresses are correct. If you are placing your app inside a folder (e.g. https://johndoe.shinyapps.io/fooBar), don't include the folder (fooBar) in "Allowed Web Origins".
  • Click "Save"

Now let's go to R!

Step 4: Create your shiny app and fill the _auth0.yml file

  • Create a configuration file for your shiny app by calling auth0::use_auth0():
auth0::use_auth0()
  • You can set the directory where this file will be created using the path= parameter. See ?auth0::use_auth0 for details.
  • Your _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")
  • Run 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.

  • Save and restart your session.
  • Write a simple shiny app in a 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").

Step 5: Run!

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.


Environment variables and multiple Auth0 apps

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:

  • (Recommended) Add environment variables inside the repository of your application, using usethis::edit_r_environ("project").
  • (Not recommended) Add the Client ID and Secret directly in the _auth0.yml file:

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:

ui.R

library(shiny)
library(auth0)

auth0_ui(fluidPage(logoutButton()))

server.R

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.


Audience parameter

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.


RStudio limitations

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.


Bookmarking

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.


Managing users

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.


Logged information

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.

Logged information and ui.R/server.R

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:

global.R

a0_info <- auth0::auth0_info()

ui.R

library(shiny)
library(auth0)

auth0_ui(fluidPage(), info = a0_info)

server.R

library(auth0)

auth0_server(function(input, output, session) {

  observe({ 
    print(session$userData$auth0_info) 
  })
  
}, info = a0_info)

Logout

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)

Costs

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.

Disclaimer

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.


Roadmap

{auth0} 0.2.0

  • [✔] Remove the need for local and remote URLs in the config_file.
  • [✔] Solve bookmarking and URL parameters issue (Issue #22).
  • [✔] shinyAppDirAuth0() function to work as shiny::shinyAppDir() (Issue #21).
  • [✔] Support to ui.R/server.R apps.

{auth0} 0.3.0

  •  Implement {auth0} API functions to manage users and login options throusgh R.
  • [✔] Hex sticker.

Download Details:

Author: Curso-r
Source Code: https://github.com/curso-r/auth0 
License: View license

#r #auth0 #authentication #hacktoberfest 

Auth0: Authentication in Shinyapps using Auth0 Service

OAuth 2.0 Spring Boot Client Deployment & MySQL Integration

Spring Boot OAuth 2.0 Client + MySQL

1. What is OAuth 2.0 ?

The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service.

2. How does OAuth 2.0 work ?

img.png

  • Resource Owner

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.

  • OAuth 2.0 Client

An application making protected resource requests on behalf of the

resource owner and with its authorization.

  • Authorization server

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.

  • Resource Server

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.

3.Technologies

Spring Boot Web

Spring Data JPA

Spring Security

Spring OAuth2 Client

MySQL Database

Docker ( Optional )

4. File Structure

img_3.png

  • 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.

5. How to run the project

Step 1 : OAuth 2.0 credentials from the Google API Console

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

Step 2 : Creating a MySQL Database Instance

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

Step 3 : Running the spring application


DEMO

Let's demonstrate with our oauth 2.0 client implementation with some basic html template.

img_1.png

Before we proceed to the authorization server , let's show our current state of the database :

img_2.png

As we can see our user table is currently empty and our goal is to create a new user after the login success.

img_3.png

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.

img_4.png

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 .

img_5.png

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.

img_6.png

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

OAuth 2.0 Spring Boot Client Deployment & MySQL Integration
Anne  de Morel

Anne de Morel

1658863800

Configurer Des Applications à Page Unique Avec Auth0

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.

Architecture d'application simple

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.

Schéma d'architecture SPA simple

Application simple avec Auth0

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).

SPA avec schéma d'architecture Auth0

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.

Auth0 dans l'environnement local

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 avons besoin de HTTPS partout

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=truevotre 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 .envfichier et de react-scriptsles récupérer automatiquement pendant le mode de développement.

SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem

Nous ne pouvons pas être sur localhost

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 localhostaussi.

127.0.0.1  localhost example.site

CORS, CORS, CORS

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));

...

Service alternatif à auth0

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. 

Source : https://blog.hao.dev/how-to-setup-single-page-applications-with-auth0-in-local-environment-without-cors-issues

#auth0 

Configurer Des Applications à Page Unique Avec Auth0

Configurar Aplicativos De Página Única Com Auth0 No Ambiente Local

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.

Arquitetura de aplicativo simples

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.

Diagrama de arquitetura SPA simples

Aplicativo simples com Auth0

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).

SPA com diagrama de arquitetura Auth0

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.

Auth0 no ambiente 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.

Precisamos de HTTPS em todos os lugares

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=trueo 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 .envarquivo e react-scriptsbuscá-lo durante o modo de desenvolvimento automaticamente.

SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem

Não podemos estar no localhost

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 localhosttambém assumem.

127.0.0.1  localhost example.site

CORS, CORS, CORS

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));

...

Serviço alternativo para auth0

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. 

Fonte: https://blog.hao.dev/how-to-setup-single-page-applications-with-auth0-in-local-environment-without-cors-issues

#auth0 

Configurar Aplicativos De Página Única Com Auth0 No Ambiente Local
Diego  Elizondo

Diego Elizondo

1658860200

Configurar Aplicaciones De Una Sola Página Con Auth0 En Entorno Local

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.

Arquitectura de aplicación sencilla

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.

Diagrama de arquitectura SPA simple

Aplicación sencilla con Auth0

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).

Diagrama de arquitectura SPA con Auth0

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.

Auth0 en el entorno 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.

Necesitamos HTTPS en todas partes

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=truesu 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 .envarchivo y react-scriptslo recogerá automáticamente durante el modo de desarrollo.

SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem

No podemos estar en localhost

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 localhosttambién asumen.

127.0.0.1  localhost example.site

CUERPO, CUERPO, CUERPO

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));

...

Servicio alternativo a auth0

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. 

Fuente: https://blog.hao.dev/how-to-setup-single-page-applications-with-auth0-in-local-environment-without-cors-issues

#auth0 

Configurar Aplicaciones De Una Sola Página Con Auth0 En Entorno Local
Hoang  Kim

Hoang Kim

1658858880

Thiết Lập Các ứng Dụng Trang Đơn Với Auth0

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ộ.

Kiến trúc ứng dụng đơn giản

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.

Sơ đồ kiến ​​trúc SPA đơn giản

Ứng dụng đơn giản với Auth0

Đâ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).

Sơ đồ kiến ​​trúc SPA với Auth0

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ộ.

Auth0 trong môi trường 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 ta cần HTTPS ở mọi nơi

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=truelệ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 .envtệp của mình và react-scriptssẽ tự động chọn nó trong chế độ phát triển.

SSL_CRT_FILE=../../cert.pem
SSL_KEY_FILE=../../key.pem

Chúng tôi không thể ở trên localhost

Để 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, CORS, CORS

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));

...

Dịch vụ thay thế cho auth0

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í. 

Nguồn: https://blog.hao.dev/how-to-setup-single-page-application-with-auth0-in-local-enosystem-without-cors-issues

#auth0 

Thiết Lập Các ứng Dụng Trang Đơn Với Auth0
郝 玉华

郝 玉华

1658856600

在本地环境中使用 Auth0 设置单页应用程序

我最近在单页应用程序 (SPA) 端项目中使用了 Auth0,因为我不想花时间构建所有与身份验证相关的功能,例如密码重置、注册等。令人惊讶的是,让它工作起来非常痛苦由于 HTTPS、CORS 和 localhost 问题而在本地进行。在这篇博文中,我将介绍我的最终设置,所有这些都在本地工作。

简单的应用架构

我将在我的项目中使用简单且非常标准的应用程序架构。我想将前端与后端分开,因为我不想要服务器端渲染 (SSR)。当用户访问我的网络应用程序时,我希望前端调用后端以获取任何数据。

在这种情况下,我在前端使用 React (create-react-app),在后端使用 Node express 服务器。

简单的SPA架构图

带有 Auth0 的简单应用程序

这是一个更新的图表,其中添加了 Auth0。现在流程有点复杂。当有人访问我的网络应用程序时,我现在想将他们重定向到 Auth0 进行注册或登录,然后再返回我的应用程序以继续用户旅程(图中的步骤 1、2 和 3)。

当用户想要编辑任何应用程序数据时,前端将附加来自 Auth0 的不记名令牌并将其与请求一起发送到后端(步骤 4 - 5)。然后,后端将通过使用该不记名令牌调用 Auth0 来验证用户是他们声称的身份,然后如果一切正常,则将数据返回到前端(步骤 6 - 8)。最后,前端将在浏览器上显示更新后的 UI(步骤 9)。

带有Auth0架构图的SPA

与我们开始的流程相比,此流程更加复杂,但它仍然非常标准。任何类型的身份验证服务或单点登录 (SSO) 都将涉及类似的过程。现在进入更复杂的部分 - 本地设置。

本地环境中的 Auth0

虽然 Auth0 在他们的网站上专门有一个Test Applications Locally部分,专注于本地应用程序测试,但不幸的是,就文档而言,它是非常基本的。很难确定他们指的是哪种类型的应用程序架构。据我了解,这部分似乎适用于 SSR 应用程序,而不是 SPA。还有一个关于开发中的 HTTPS的部分(我稍后会解释为什么我们需要 HTTPS),我敢肯定这不适用于上图中的架构。

长话短说,我在 Auth0 的网站上没有找到任何好的指导,所以我不得不自己打造。

我们到处都需要 HTTPS

如果我们的前端在 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 的替代服务

如果您正在考虑使用 Auth0,我遇到了另一个名为Magic的服务,它似乎提供了更好的整体开发体验。他们的本地环境设置好得令人难以置信,请在此处查看。然而,我最后选择 Auth0 的原因是因为他们慷慨的免费套餐最多允许 1000 个活跃用户。相比之下,Magic 根据用户登录次数收费,并且没有免费限额。 

来源:https ://blog.hao.dev/how-to-setup-single-page-applications-with-auth0-in-local-environment-without-cors-issues

#auth0 

在本地环境中使用 Auth0 设置单页应用程序
山岸  英樹

山岸 英樹

1658855040

ローカル環境でAuth0を使用してシングルページアプリケーションをセットアップする

最近、シングルページアプリケーション(SPA)サイドプロジェクトでAuth0を使用しました。これは、パスワードのリセットやサインアップなど、認証に関連するすべての機能を構築するために時間を費やしたくなかったためです。驚くべきことに、Auth0を機能させるのは非常に苦痛でした。 HTTPS、CORS、およびlocalhostの問題が原因でローカルに発生します。このブログ投稿では、すべてがローカルで機能するように、最終的なセットアップについて説明します。

シンプルなアプリアーキテクチャ

プロジェクトでは、シンプルで非常に標準的なアプリアーキテクチャを採用します。サーバーサイダーレンダリング(SSR)が必要なかったため、フロントエンドをバックエンドから分離したかったのです。ユーザーが私のWebアプリにアクセスしたときに、フロントエンドがデータのバックエンドを呼び出すようにします。

この場合、フロントエンドでReact(create-react-app)を使用し、バックエンドでNodeExpressサーバーを使用しています。

単純なSPAアーキテクチャ図

Auth0を使用したシンプルなアプリ

これは、Auth0が画像に追加された更新された図です。これで、フローはもう少し複雑になります。誰かが私のWebアプリにアクセスしたときに、サインアップまたはサインインするためにAuth0にリダイレクトしてから、アプリに戻ってユーザージャーニーを続行したいと思います(図のステップ1、2、3)。

ユーザーがアプリデータを編集する場合、フロントエンドはAuth0からベアラートークンを添付し、リクエストとともにバックエンドに送信します(ステップ4〜5)。次に、バックエンドは、そのベアラトークンを使用してAuth0を呼び出すことにより、ユーザーが本人であると主張していることを確認し、問題がなければデータをフロントエンドに返します(手順6〜8)。最後に、フロントエンドは更新されたUIをブラウザーに表示します(ステップ9)。

Auth0アーキテクチャ図を使用したSPA

このフローは、私たちが始めたものと比較してより複雑ですが、それでもかなり標準的です。あらゆる種類の認証サービスまたはシングルサインオン(SSO)には、同様のプロセスが含まれます。次に、より複雑な部分であるローカルセットアップに移ります。

ローカル環境のAuth0

Auth0は、ローカルアプリのテストに焦点を当てたWebサイトのTest Applications Locallyセクションを用意していますが、残念ながら、ドキュメントに関する限り、これはかなり基本的なものです。参照しているアプリアーキテクチャのタイプを特定するのは困難です。私が理解している限り、このセクションはSPAではなくSSRアプリ向けのようです。開発中のHTTPSに関するセクションもあります(HTTPSが必要な理由については後で説明します)。これは、上の図のアーキテクチャには当てはまらないと確信しています。

非常に長い話ですが、Auth0のWebサイトで適切なガイダンスが見つからなかったため、自分で作成する必要がありました。

どこでもHTTPSが必要

フロントエンドが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、CORS、CORS

ローカル環境の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の代替サービス

Auth0の使用を検討している場合は、Magicと呼ばれる別のサービスに出くわしました。これは、全体としてはるかに優れた開発エクスペリエンスを提供しているようです。彼らのローカル環境のセットアップはあまりにも良すぎるようです。ここでチェックしてください。ただし、最後にAuth0を使用した理由は、最大1000人のアクティブユーザーを許可する寛大な無料利用枠のためです。マジックの比較料金はユーザーログイン数に基づいており、無料の手当はありません。 

ソース:https ://blog.hao.dev/how-to-setup-single-page-applications-with-auth0-in-local-environment-without-cors-issues

#auth0 

ローカル環境でAuth0を使用してシングルページアプリケーションをセットアップする

Setup Single Page Applications with Auth0 in Local Environment

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.

Simple app architecture

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

#auth0 

Setup Single Page Applications with Auth0 in Local Environment