Why does my Auth0 id_token not contain any information about the user? - reactjs

I started from this React sample application from Auth0 and login through Auth0 works fine but does not give me the expected token.
After login the browser localStorage contains an id_token and a profile object. When I decode the id_token I see that the payload contains something like this:
{
"iss": "https://mycompany.eu.auth0.com/",
"sub": "auth0|5821bc27f92ca3261c628a26",
"aud": "2A8cgDBm86kLCtCNtUMcKPL2G3oqjIdE",
"exp": 1478755859,
"iat": 1478719859
}
The profile contains email and lots of other good stuff from the user profile as registered in Auth0.
I need to parse on the token to my API server and therefore I need the attributes from the profile-object to be part of the token. How can I make the id_token contain all these attributes, so that I can parse it in my API-service and store it the first time the user logs in?
As I see it, I cannot use the profile-object found in the browser localStorage as it needs to be signed by Auth0 in order for my API server to trust the information.
I'm also aware that I can use the id_token to make a request from my API server directly to Auth0 to get this additional information, but I just think it would be simpler and more efficient if the information was carried by the token.

Those are the claims included by default in a id_token; it's possible to request other claims to be included by passing a scope parameter with the appropriate value.
See Scopes - Requesting specific claims, for a reference on what you can pass in the scope parameter in order to influence the contents of the id_token.

To add onto João Angelo's answer, you can't request the entire "App_Metadata" object in scope. If there are app specific fields e.g. lang or favorite color, these have to be called out specifically.
Example App MetaData
Example call
https://example.auth0.com/authorize
?response_type=token
&client_id=YOUR_CLIENT_ID
&redirect_uri=http://jwt.io&connection=google-oauth2
&scope=openid+lang+favoriteColor
There may be additional caveats to the scope parameter, it would be good to ask Auth0 as you run into issues

Related

Get custom policy name based on authorisation code

I am using Active Directory B2C to authenticate users. We are leveraging on code flow.
We have 3 custom policies defined and each of them has it's own token endpoint.
I would like to dynamically infer the token endpoint based the the code received e.g.
https://<tenant domain>/oauth2/v2.0/token?p=<here goes the policy name>
Is it possible to infer that based on the authorisation code?
I was looking into to, but it looks like there is nothing inside telling the policy name. Literally it's just few basic info in header in JSON format and bunch of other characters that are not base64 encoded.
Finally we came with a different solution but I can share the idea that worked for above problem.
When a user starts a custom policy we pass it to state query parameter. Then when B2C calls code endpoint with provided state parameter we read the policy name from it and use it to build the right token endpoint.

How to retrieve access tokens without AdalJS?

I registered an application in Azure AD.
How can I get access tokens Programmatically without using AdalJS library in JavaScript?
Thank you!
You would have to use the implicit grant flow manually.
You can see some basic documentation here: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-authentication-scenarios#single-page-application-spa.
You'd authenticate the user by redirecting them to sign in, for example https://login.microsoftonline.com/yourtenant.onmicrosoft.com/oauth2/authorize?client_id=your-client-id&response_type=id_token&redirect_uri=https%3A%2F%2Flocalhost&nonce=abcdef.
Of course you'll need to replace values with your corresponding values.
And generate a unique nonce for each request.
Once the user comes back, you'll need to grab the id_token from the fragment and decode it to get the user info.
Then you can acquire access tokens for APIs with a hidden iframe with a very similar URL as before, but this time with response_type=token&prompt=none&resource=https%3A%2F%2Fgraph.microsoft.com%2F.
Replace the resource with the resource URI/id that you want a token for.
Then you will have to listen for the URL change of the iframe and grab the access token from its fragment when it returns successfully (or parse the error in case authentication fails).
ADAL.JS hides a lot of this complexity from you so I'd strongly advise using it if possible.
It didn't work for me, so I use ADAL. I added script on my page using ScriptLink custom action and acquire token there. WHen adal adds iFrame with the link, I redirect there and it navigates me back to my page with parameters in hash (url), so my script retrieves token from urls hash.

Do we really need id_token in implicit flow in OIDC?

I'm working on a SPA application, and I'm using the recommended implicit flow and I'm able to get access_token and id_token. As I need more than the profile info, I've created a separate endpoint to return the user profile information (along with all the other information that's specific to our business) and this endpoint is protected, and can be accessed only with an access_token as the bearer token. Right after getting access_token in SPA, I call this endpoint to get all the user information (which includes first name, last name etc., that gets displayed on the UI). If there is any problem with the returned id_token and access_token pair, the user profile info endpoint call would fail. So, do I really need to validate the id_token? as I'm not relying on any information within that token.
For authenticating against external login provider or authorization code flow, validating the id_token makes sense, but in my case I'm not sure about it.
According to OpenID spec:
When using the Implicit Flow, the contents of the ID Token MUST be validated in the same manner as for the Authorization Code Flow, as defined in Section 3.1.3.7, with the exception of the differences specified in this section.
1. The Client MUST validate the signature of the ID Token according to JWS [JWS] using the algorithm specified in the alg Header Parameter of the JOSE Header.
2. The value of the nonce Claim MUST be checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific.
Why don't you utilise response_type parameter in authorisation request. By changing its value, you can alter what you receive for authorisation response.
Identity documentation mention about possible response type values. Following is an extraction from their documentation,
As you can see, if you do not want SPA to receive the id token, you can set the response_type value to token. If you do so you will only get an access token, which is enforced by OAuth 2.0 specification. (See the OAuth 2.0's implicit flow response_type explanation from here). Note that when you use response_type=token , you are using OAuth 2.0 (not OIDC)
I don't see any wrong in your approach as long as you utilise features enabled by respective protocols.

Azure AD - adaljs...how to use this library?

I'm using adaljs. Everything seems great...I can log in, log out, wonderful.
Now, after an hour...I load up my app again and! NOT so wonderful. I debug and I see that adalAuthenticationService.userInfo.isAuthenticated == false and adalAuthenticationService.profile == undefined.
What do I do when I get this? How do I recover?
When do I use these functions and for what?
acquireToken
clearCache
clearCacheForResource
getCachedToken
getResourceForEndpoint
getUser
logOut
logIn
logOutInProgress
Most importantly, WHY are these not explained in detail (or even in brief!) on the adaljs repository?
Let's turn this into a wiki about adaljs functions and properties. We all want to know what they do, what they are for, and how to use them.
Edit
In my app.js, I have this code for handling authentication:
if (adalAuthenticationService.userInfo.isAuthenticated && adalAuthenticationService.userInfo.profile) {
var great = "everything is awesome";
_ld.extend($scope.user,adalAuthenticationService.userInfo);
$scope.successFullyLoggedIn($scope.user);
} else if(!adalAuthenticationService.userInfo.isAuthenticated && !adalAuthenticationService.userInfo.profile) {
adalAuthenticationService.clearCache();
adalAuthenticationService.login();
} else {
adalAuthenticationService.clearCache();
adalAuthenticationService.logOut();
}
The tokens that adal.js gets from AAD expires after every one hour. If you are using angular wrapper then adal will be able to automatically renew the tokens as long as there is a valid user logged in. If you are not using angular wrapper, then application has to take the responsibility of renewing the tokens, that is where the apis will come handy.
I will try to explain what each one of them do:
acquireToken: This is one of the main methods. Takes 2 parameters: resourceId and callback. ResourceId is the app id of application on azure portal. Adal first looks into cache to check if there is token present already. If not, it sends a request to AAD to get a new token. It passes the token or the error to the callback, which has a signature like this: callback(err, token).
clearCache: delete all items in the browser storage that adal stored. Kind of a fresh start.
clearCacheForResource: I am assuming you are using experimental version because this api is not part of released 1.0.12 version. This basically deletes the cache entries for a specific resource id.
getCachedToken: Looks into the caceh and returns the token or null for the given resource.
getResourceForEndpoint: This is useful when using angular wrapper. This looks into the endpoints mapping that user provided at the time of initializing adal. The purpose of this method is to resolve a url into resourceId which can then be fed to acquireToken method.
getUser: current logged in user object or null.
logOut: logs out the user, clears cache and redirect the user to postlogoutredirecturi (if specified), otherwise redirects the user to redirecturi.
login: logs in the user, creates the user object (which can be accessed using getUser), saves the id token in the cache. It also calls the callback that you have on application level on config object when initializing adal.
logOutInProgress: Do you mean loginInProgress? That is just a flag to use internally to see if there is an active login in progress.
Unfortunately, we do not have api guides, that can help people understand our apis better. I will bring this to team's notice. Thanks.
Back to your question: you can use getUser() to get the user object. If it is null, then call logIn() method to log in the user. If user.userName is not null but user.isAuthenticated is false, this means, the token has expired, call acquireToken method and pass clientId of the application to renew the token. Also, you want to check adalAuthenticationService.usernInfo.profile instead of adalAuthenticationService.profile.

What is the OAuth scope for the Google Translation API?

Surely someone else is using the API, I've looked and searched, I cannot seem to find the correct value to place for the scope parameter when authenticating:
I've looked at all these scope lists, nothing, tried the OAuth 2.0 playground, translation is not there.
oauth playground v1
oauth playground v2
oath supported scopes
auth scopes
Any clues welcomed, thank you.
Error message:
Error: invalid_request
Missing required parameter: scope
Learn more
Request Details
Update
User Ezra explained that OAuth2 authentication is not needed for the Translation API.
I got down this road by this path:
I was trying to make the sample code here work:
translation api sample code
And didn't have the apiclient.discovery module
from apiclient.discovery import build
I went off looking for that which landed me here to this quick-start configurator
which gave me an autogenerated translation api project here:
This starter project which is supposed to be tailored for Translation API includes a whole bunch of OAuth configuration and so I wound up asking the question because of the error mentioned here
exception calling translation api: <HttpError 400 when requesting https://www.googleapis.com/language/translate/v2?q=zebra&source=en&alt=json&target=fr&key=MYSECRETKEYWENTHERE returned "Bad Request">
The code I'm using to make said call which errors out in this way is:
service = build('translate', 'v2',
developerKey='MYSECRETKEYWENTHERE')
result = service.translations().list(
source='en',
target=lang,
q='zebra'
).execute()
If I make the same call directly that the error complains about, it works ok
https://www.googleapis.com/language/translate/v2?key=MYSECRETKEYWENTHERE&q=zebra&target=fr&alt=json&source=en
Updated Again
Okay, I removed all the OAuth code from the sample project and then ran it again and then finally noticed that I had a typo in my secret key... donk
Thanks for the answers!
.
Thank you
I think you are misunderstanding what OAuth scopes are for. You didn't list any of your code, so I'm going to explain some concepts, and hope that you can apply them to your situation.
OAuth Scopes explained:
The purpose of OAuth scopes is accessing information about authenticated users. The scopes are different for each applications, and determine what information about a user that an application is granted access to.
Concretely, an OAuth request with the scope parameter as
https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
Would show the user a prompt similar to the following when logging in:
+ View basic information about your account
* View your name, public profile URL, and photo
* View your gender and birthdate
* View your country, language, and timezone
+ View your email address
* View the email address associated with your account
While one with only https://www.googleapis.com/auth/userinfo.email would show something like:
+ View your email address
* View the email address associated with your account
Translate API explained:
To use the Translate API, you don't have to have users authenticated with OAuth. You simply get an API Key, and provide that key in your request to the service.
The use of the Translate API is completely orthogonal to the use of OAuth.
As documented on the Translate API site, to translate something you simply make a request to
https://www.googleapis.com/language/translate/v2?parameters
with the appropriate parameters.
The parameters needed are, as listed in the documentation, the
API key. Use the key query parameter to identify your application.
Target language. Use the target query parameter to specify the language you want to translate into.
Source text string. Use the q query parameter to identify the string to translate.
Concretely, a request to translate the text "hello world" into German would be:
https://www.googleapis.com/language/translate/v2?key=INSERT-YOUR-KEY&source=en&target=de&q=Hello%20world
Look at the parameters specification to get an idea of what you have to supply.
What to do:
Look at the source of the Python example using the Translate API or look up the API library for the language you want to use.
You'll see in the examples that there is no mention of OAuth scopes, because it's not needed to authenticate against the Translate API service. You only need to provide your API key, and the text to be translated in your request to the service.
There may be API calls that require scope, but Translate is not one of them.
If there is some piece of information about a user that you need, you will have to look up the API and Scope needed to access that piece of information. You will then supply this information to the Translate API as necessary.
In case of 400:
If you are getting an error response, that's good, because the call to the service is working, even if it's not doing what you want.
In the case of a 400, the Translate API's response will give you a clue about your error in its response.
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "keyInvalid",
"message": "Bad Request"
}
],
"code": 400,
"message": "Bad Request"
}
}
The response above indicates that the key is invalid. You can request a new one (or find out your old one) through the Google API Console.
Summary:
OAuth scopes are used for requesting information about a user. You will have to identify the scope when authenticating the user, and you will have access to all information provided by those scopes.
The Translate API doesn't need a scope. You provide an API Key (and some other information) in your request, and it gives back the translation as documented.
If there is information about a user that you wish to translate, it must be done in two steps. First, collect the information by authenticating the user in the appropriate scope, and second by providing that information to the Translate API.
If you're getting a 400, the response will include some information you can use to debug the problem.
According to Google's documentation, you have to look at the documentation for your specific API.
Update as per this Google Group question:
"The Translate API (both v1 and v2) is an unauthenticated API, so you don't need to use OAuth with it. Instead, for v2, you should use an API key, which you can get here: http://code.google.com/apis/console"
For error message
Error: invalid_request
Missing required parameter: scope
You need to add scopes in your form
<input type="hidden" name="scope" value="https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo#email https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/tasks https://www-opensocial.googleusercontent.com/api/people https://www.googleapis.com/auth/plus.login" />
Please refer spring social login with linkedin,facebook,twitter and google providers.

Resources