Hello and thanks in advance for the hints.
I’m working on a project composed by a React FE application which query a gal-server.
The gql-server has some BE micro-services as datasources.
We would like to implement the following flows without using any FE plugin and so using the embedded login:
- Login / Signup
- Auth / Authz
- Invitation flow (for back office users)
My idea is to create a BE micro-service which acts as my gql-server auth0 datasource.
So for example the FE application will call the login mutation along with the user credentials on the gql-server which will use the BE micro-service as datasource in order to retrieve the access token and auth the next mutation.
Does it make sense?
In this scenario I would refer to the BE micro-service as the a “confidential” auth0 client. Is it correct?
Which kind of Application should I create in the auth0 dashboard Application tab?
Based on it I would implement the resource owner password flow (Authentication API Explorer), does it make sense?
Hello, @andrea.speziale - welcome to the Auth0 Community!
In this cases, you need to ask yourself:
- Is the entity contacting Auth0, contacting it directly? Or is it using a middleman (such as a browser)? Is the entity contacting Auth0, in turn secure?
- Who is the entity requesting access on behalf of? Itself, of the user?
With that, here are some possible combos:
- With middleman (browser, not-so-secure), on behalf of the user: Authorization Code Flow (maybe with PKCE)
- No middleman (contacting from the server directly), on behalf of the user: Resource Owner Password Grant
- No middleman (contacting from the server directly), on behalf of itself: Client Credentials Grant
And these are just some examples. The idea is to play with some variables, and depending on those, decide what’s the best flow depending on your scenario.
Let me know if this helps clarify the situations!
Hello @joseantonio.rey I got you.
Please take a second to check the following diagram which is my proposal.
The auth/authz connector would be some kind of library which is capable to eventually switch btw auth/authz strategies and initially it will wrap auth0 (maybe using auth0 sdk).
I think that in the described scenario the Resource Owner Password Grant would be the best fit.
How does it sound?
Still based on the scenario which kind of Application should I create in the auth0 dashboard?
(I believe a Single Page Web Application even if we are talking of something more BE oriented)
Thanks
Hey @andrea.speziale,
If the contact is direct between the connector and Auth0, then yes, you could use the Resource Owner Password Grant.
The type of application you would have to set in this case would be Regular Web App. Single Page Apps are much more limited in this scope, and since they are considered insecure, they wouldn’t be able to perform an ROPG.
@joseantonio.rey Thanks for confirming!
I’ve a question related to the JSON Web Key Sets.
Is it really necessary to retrieve public keys from https://your_domain/.well-known/jwks.json?
I mean, would it be the same to download the file and avoid the API call?
I’m asking it because in my understanding it means that otherwise I wouldn’t be able to perform the token validation without being expose to the internet. Is that correct?
@joseantonio.rey It seems there is no secret to be used in BE side for token validation.
jwks
is about checking the jwt
signature against a list of public keys using the incapsulated kid
property.
Based on the upper scenario I think the best solution would be:
- setup the micro-services to block external incoming requests and to allow outgoing traffic
- use
jwks
https://your_domain/.well-known/jwks.json
endpoint to perform token validation
- create a scheduled job which periodically save the
jwks.json
file in a storage so it can be used as fallback strategy in case of the upper endpoint wont work
More in general I’ve been able to setup and test the signup and login flow using Postman but it seems the realm
option in the /oauth/token
endpoint isn’t really working.
I have:
- specific connection (database)
- regular web application
and the flow is only working while using the default Username-Password-Authentication
connection.
If I try to turn off the Username-Password-Authentication
connection in the Application settings and just turn on my specific connection it wont find the user while getting the access token (/oauth/token
)
In order to make the flows work, at least with the Username-Password-Authentication
connection I had to setup Username-Password-Authentication
as Default Directory
in the Tenant settings.
How can I restrict the usage of a specific connection (database) in the signup/login flows?
Hello, @andrea.speziale,
Have you taken a look at this section of our documentation? Setting up Realm support is a bit more complex, but is definitely achievable: Call Your API Using Resource Owner Password Flow
JWKS should be cached, as you mentioned. This endpoint is available so that, if you rotate your signing key due to a leak or just do it for funsies, you know that the previous key is no longer valid, and know what the current key is.
@joseantonio.rey Thanks for the support. In order to continue on testing the flow using Postman I’ve
- created a regular web application client
- created an API which as Machine to Machine Application authorizes only the above client
- signup a User (√)
- login the User (√)
- tested with the following snippet the authentication sending as Bearer Token the ID Token returned by the above login API call
import { Request, Response } from 'express'
var express = require('express')
var app = express()
var jwt = require('express-jwt')
var jwks = require('jwks-rsa')
var port = process.env.PORT || 8080
var jwtCheck = jwt({
secret: jwks.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: 'MY_DOMAIN/.well-known/jwks.json',
}),
audience: 'MY_AUDIENCE',
issuer: 'MY_DOMAIN',
algorithms: ['RS256'],
})
app.use(jwtCheck)
app.get('/authorized', function (req: Request, res: Response) {
res.send('Secured Resource')
})
app.listen(port)
As result:
UnauthorizedError: jwt audience invalid.
Actually the audience incapsulated in the JWT payload returned by the login API call is not the one defined as API in the auth0 dashboard. It’s actually the client ID.
What I’m doing wrong? Or what I’m miss-understanding?
Hello, @andrea.speziale,
In order to continue, we need to understand a couple of things:
1.- We have the Access Token and the ID Token. The Access Token is meant for accessing a resource, while the ID Token is meant for profile caching in the application. You are parsing the ID Token, which has the Client ID as the audience.
2.- We have two types of tokens: opaque tokens and JWT tokens. If the audience is an internal Auth0 service (except our Management API v2), the token returned will be opaque (a random string only the Authorization Server can understand). If the audience is something different, it will be a JWT.
I think that in this specific event you want a JWT Access Token. In your authentication event (/authorize
request), you have to specify the audience
parameter. Could you please give that a try?
@joseantonio.rey
1 is correct. I’m actually using the ID Token since it is in JWT format and the access-token has a different format.
Calling the auth0 /oauth/token
API endpoint using as grant_type
password
I’m getting back the following:
{
"access_token": "RpBlFTAaSsTBDkoy........", // not JWT
"id_token": "eyJhbGciOiJSUz.......", // JWT
"scope": "openid profile email address phone",
"expires_in": 86400,
"token_type": "Bearer"
}
If I pass to the previous code snippet the access token I get back and error saying that it isn’t in the JWT format.
2 I would say I’m receiving an opaque token. As mentioned I created an API in the auth0 API function and I’ve restricted the authorization to the Application I’ve created in the auth0 Application dashboard.
How are Client Application and API connected somehow? Shouldn’t the login through a Client Application return something which should be validated using a specific API?
Hello, @andrea.speziale,
The Application and the API are not connected in any way until you specify the identifier of the API as the audience
parameter in your authentication request (/authorize
). A client can have multiple APIs associated, which is why you need to specify the audience.
If you don’t specify the audience, we will use our default audience, which is an Auth0 audience, and, in turn, returns an opaque token.
Please, try setting an audience for your authentication request. This should solve your issues.
@joseantonio.rey Thanks again.
If they are not connected through the API “machine to machine” authorization tab setting what is it for?
Is it preventing an API to be called from an Application which may inadvertently sets the API audience
?
I’m also confused by the /authorize
endpoint usage.
I’m actually using
- for signup =>
/dbconnections/signup
passing client_id
, email
, password
and connection
- for login =>
/oauth/token
passing grant_type
as password
, client_id
, username
, password
, client_secret
and yes, I was missing audience
Setting the audience
and the scope as openid
the response actually change in:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkU0X3JyeWJ0TWhYTC1JQzFkaDliZSJ9.eyJpc3MiOiJodHRwczovL2xlbmRib3gu...", // JWT
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6....", // JWT
"scope": "openid profile email address phone",
"expires_in": 86400,
"token_type": "Bearer"
}
And it seems correct. So my micro-service will receive Authorization
: Bearer access_token_value
but the user information are in the ID Token. Should I send it in an other header? Because instead I don’t see how I could eventually check (eg) roles and permission attached to the User
Hello, @andrea.speziale,
The setting you mention is to set the default audience when making Machine to Machine requests because a machine can not click on a prompt
The Access Token can contain multiple audiences. If it has the your.tenant.domain/userinfo
endpoint as an audience, you can use that token to call that endpoint, which will return the user profile in real time (except for the email verification status, which is a snapshot at the time of token generation).
Hello @joseantonio.rey,
I didn’t really get your Access Token
explanation.
I’ve found the following auth0 blog post / tutorial
Based on it my understanding is that my auth0 will send to my back-end both, the Access Token
and the ID Token
.
- the
Access Token
will be used to authenticate and eventually authorize the next API call (the eventually roles and permission must be manually added by auth0 rules)
- the
ID Token
can be used by the FE to draw the UI based on the incapsulated user info
Is my understanding correct?
I’m also not understanding the auth0 /logout
endpoint.
I believe it wont be useful in my case since my app is a stateless app using the Resource Owner Password Flow managed by my back-end.
So the question is, how I invalidate the tokens which are still valid even if my user explicitly logout? I believe that the authentication would say “everything ok” If I don’t track those kind of tokens. Is it auth0 handling it somehow?
Thanks in advance
Hello, @andrea.speziale,
Once a token is generated, it is not possible to modify it in any way, including to invalidate it. Your application would have to have logic to handle that.
I recommend that you read this document, which I really enjoy, to understand what I call “The Three Layers of Logout”: Logout
Hello @joseantonio.rey, and thanks for the inputs. I already checked that page but since I’m aiming to create a stateless app (without dealing with third parties login) I believe that the session topic doesn’t apply in my use case.
By the way understood, If I want to prevent that an access token is used multiple times is my application concern.
What I can do with auth0 is dealing with refresh tokens. They can be actually invalidated to avoid to be used to renew access tokens.
So resuming I would say
- access token useful to the back-end in order to check authorization and eventually permissions which will be add automatically if the proper API setting is checked
- id token which contain user info and so useful to the front-end. In order to add also the role as custom claim a Rule should be created
- refresh token in order to renew access token under the hood
Should we somehow also check the ID Token somewhere since it is a JWT?
Am I missing something?
Thanks again
Still nothing?
Thanks in advance