I am attempting to do this call from my spring backend api. I already have the access token which the client sent me. What is the java-equivalent of this code?:
// Script uses auth0.js. See Remarks for details.
<script src="https://cdn.auth0.com/js/auth0/9.0.1/auth0.min.js"></script>
<script type="text/javascript">
// Initialize the Auth0 client
var webAuth = new auth0.WebAuth({
domain: '{domain}',
clientID: '{clientId}'
});
// Parse the URL and extract the access_token
webAuth.parseHash(window.location.hash, function(err, authResult) {
if (err) {
return console.log(err);
}
webAuth.client.userInfo(authResult.accessToken, function(err, user) {
// This method will make a request to the /userinfo endpoint
// and return the user object, which contains the user's information,
// similar to the response below.
});
});
</script>
Details in access token from client (I removed some of the details and replaced them with square brackets):
~~~~~~~~~ JWT Header ~~~~~~~
JWT Header : {"typ":"JWT","alg":"RS256","kid":"[kid]"}
~~~~~~~~~ JWT Body ~~~~~~~
JWT Body : {"iss":"https://demo.auth0.com/","sub":"google-oauth2|[my id here]","aud":["[api audience]","https://demo.auth0.com/userinfo"],"iat":[number],"exp":[expiry],"azp":"[azp]","scope":"openid"}
It is just a standard https call (plus adding the access token as an authorization bearer header) - no special library required.
An example making this from server-side using Node.js is here.
Basic Java outline, here using OkHttp, would be:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://mytenant.auth0.com/userinfo")
.get()
.addHeader("authorization", "Bearer {{access_token}}")
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
Related
I am trying to authenticate Spotify API using the OAuth2.0 client credentials flow. Generally the flow is as follows:
Send GET request to /authenticate endpoint with required parameters, including a callback endpoint that i have set to my http://localhost:8888/callback
const open = require('open')
responseType = 'token'
clientID = 'CLIENT_ID'
redirectURI = 'http%3A%2F%2Flocalhost%3A8888%2Fcallback'
scope = 'streaming+user-read-email+user-modify-playback-state+user-read-private+user-library-read+user-library-modify+user-read-currently-playing'
contentType = 'application/json'
params = {
'response_type' : responseType,
'client_id' : clientID,
'redirect_uri' : redirectURI,
'scope' : scope
}
headers = {
'Content-Type' : contentType
}
// send user to browser to grant data permissions
open(`https://accounts.spotify.com/en/authorize?response_type=${responseType}&client_id=${clientID}&redirect_uri=${redirectURI}&scope=${scope}&show_dialog=true`)
-- this part is fine, i have no issues sending user to browser to login and grant my app permission and the Express server i have listening on port 8888 lets me know when the callback pings with the response
Receive Authentication Token in params of callback from Authentication endpoint. Spotify API handles this part and sends the authentication token that i need as part of the header in the response. it looks like this
http://localhost:8888/callback#authentication_token=2iais820zg...fh9IHkLDI&timeout=3600
-- this is what i am having problems with.
here is my how i am handling the api callback in my Express server's /callback endpoint:
app.get('/callback', function (req, res) {
console.log('someone made a request!\n')
/// ////
console.log(req + '\n')
console.log(res + '\n')
/// ////
console.log(req.body)
res.json(req.body)
res.send('GET request to callback endpoint took you here')
res.end()
})
but the console output is as follows:
> server is listening on port 8888 ...
someone made a request!
[object Object]
[object Object]
{}
where everything is empty.
how can i access the URL parameters of the callback GET request? i have tried changing the handling from GET to POST as people have told me that a GET request doesn't contain params but the callback can't find the endpoint (bc it's not making a POST request..)
you should put the parameters into request body not in the header as you mentioned
to let you use req.body with no problem
In Nuxt.js this is one way to implement authentication :
The client authenticates by sending an HTTP request with its credentials in the body to an API route of the Nuxt backend ;
The Nuxt backend responds with a JWT token that allows the client to access protected routes ;
Finally, when the authenticated user tries to access such a route, they make an HTTP request to the Nuxt backend with their JWT token inserted in the header ;
The backend validates the JWT token and responds with the requested page JSON data to the client.
What I don't understand is how to make the Nuxt backend aware that for some protected routes it has to check the JWT token of the client before providing the page JSON data. I mean, where exactly in Nuxt can I implement this kind of validation ?
Well i am confused a bit first you say API data the other sentece you say JSON page.. however. If you want to protect an PAGE then you create an middleware
middleware/auth.js
export default async function ({ store, $axios, redirect }) {
let valid = await $axios.$post('/api/checktoken')
if (!valid) {
redirect('/')
}
}
You need to create an API where you check the token. Usually you need to put the token in your header like Authentication: Bearer token... however i simply save my token inside an cookie. Because if you send an HTTP request to the server the cookies gets automatically sended with it so i dont need to do some extra work.
Next step is you go to some page and set your middleware auth.
page.vue
<script>
export default {
middleware: "auth"
}
</script>
However if you want to protect some backend routes you can do it like this. Create again an middleware
async authenticate(req, res, next) {
let token = await cookieService.getTokenFromCookie(req)
if (!token) return errorService.resError(res, 400, 'Authorization failed')
let tokenValid = await tokenService.verifyToken(token)
if (!tokenValid)
return errorService.resError(res, 400, 'Authorization failed')
let decodedData = tokenService.decode(token)
if (!decodedData)
return errorService.resError(res, 400, 'Authorization failed')
res.locals.userId = decodedData.userId
res.locals.role = decodedData.role
next()
}
In this case you basically need to read the token out of your cookie. (in case you dont use cookies you will need to read it out of your header so for this you should create an function that reads your token out of the header)
Check if token is even there.
Verify if token is valid.
Decode the token so you can access the data in it
Now you can also put the data to your res.locals. The advantage is that this data is scoped to this current request and you can access it in the next middleware / endpoint.
then you call next() to step to the next middleware / endpoint
function endpoint(req, res) {
let { userId, role } = res.locals
do something....
}
So the route looks something like this:
app.use("/some/api/point", authenticate, endpoint)
The good thing about is you can put authenticate in every API route you want to protect.
RestAPI: I have a Rest API running Asp Core with AzureAd Authentication.
WebApp: I have a separate WebApplication running Asp Core as backend, with Javascript frontend.
The WebApp backend authenticates through AzureAd, and then against the RestAPI to check if a user is registred.
I want the javascript client to be able to consume the Rest API directly. How should i go about this without exposing the accesstoken?
I could go about sending the request from Javascript to WebApp Backend -> Rest API. But i really want to avoid this, because of unnecessary code.
In this scenario, you can try to implement ADAL for js in your JS client. Leveraging **adal** to gain the authentication token, and when you call your Web Api, it will add the authentication header in HTTP requests.
E.G.
Suppose we want to call the Microsoft Graph API from our JS client.we develop a node.js script that uses request to call the Microsoft Graph API for groups to create a new Security Group.
The following code shows how the API is consumed from that script. Note that the token and the name are passed by parameter. Additionally, this function returns a Promise that is successfully resolved when the group is correctly created and rejected when is not.
var request = require('request');
function createGroup(token, name) {
return new Promise((resolve, reject) => {
const options = {
method: 'POST',
url: 'https://graph.microsoft.com/v1.0/groups/',
headers: {
'Authorization': 'Bearer ' + token,
'content-type': 'application/json'
},
body: JSON.stringify({
"displayName": name,
"mailEnabled": false,
"securityEnabled": true
})
};
request(options, (error, response, body) => {
const result = JSON.parse(body);
if (!error && response.statusCode == 204) {
resolve(result.value);
} else {
reject(result);
}
});
});
}
In order to call Microsoft Graph API, we needed to be authenticated and that is why in the previous section we have a token as a parameter of the function which was used to perform the request.
we should add the following code to generate the token. Note that we are using the adal npm package to do this easier, calling the acquireTokenWithClientCredentials method of the AuthenticationContext object. Additionally, we have some constants that need to be updated with the client id and secret obtained before as well as the tenant name.
var adal = require('adal-node');
const TENANT = "{tenant-name-here}.onmicrosoft.com";
const CLIENT_ID = "{Application-id-here}";
const CLIENT_SECRET = "{Application-key-here}";
function getToken() {
return new Promise((resolve, reject) => {
const authContext = new adal.AuthenticationContext(`https://login.microsoftonline.com/${TENANT}`);
authContext.acquireTokenWithClientCredentials(GRAPH_URL, CLIENT_ID, CLIENT_SECRET, (err, tokenRes) => {
if (err) { reject(err); }
resolve(tokenRes.accessToken);
});
});
Hope it helps.
I need to retrieve some data from Google Search Console (Webmaster Tools) using a service account.
So far I've been able to retrieve an access_token for the service account which I need to append to the url of the request. The problem is that I can't find a way to do so, this is the code i'm using:
function retrieveSearchesByQuery(token)
{
gapi.client.webmasters.searchanalytics.query(
{
'access_token': token,
'siteUrl': 'http://www.WEBSITE.com',
'fields': 'responseAggregationType,rows',
'resource': {
'startDate': formatDate(cSDate),
'endDate': formatDate(cEDate),
'dimensions': [
'date'
]
}
})
.then(function(response) {
console.log(response);
})
.then(null, function(err) {
console.log(err);
});
}
This is the url called by the function:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json"
Instead it should be something like this:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json&access_token=XXX"
The gapi.client.webmasters.searchanalytics.query doesn't recognize 'access_token' as a valid key thus it doesn't append it to the url and that's why I get a 401 Unauthorized as response.
If I use 'key' instead of 'access_token' the parameter gets appended to the url but 'key' is used for OAuth2 authentication so the service account token I pass is not valid.
Does anyone have a solution or a workaround for this?
If your application requests private data, the request must be authorized by an authenticated user who has access to that data. As specified in the documentation of the Search Console API, your application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported.
If you application is correctly configured, when using the Google API, an authenticated request looks exactly like an unauthenticated request. As stated in the documentation, if the application has received an OAuth 2.0 token, the JavaScript client library includes it in the request automatically.
You're mentioning that you have retrieved an access_token, if correctly received, the API client will automatically send this token for you, you don't have to append it yourself.
A very basic workflow to authenticate and once authenticated, send a request would looks like the following code. The Search Console API can use the following scopes: https://www.googleapis.com/auth/webmasters and https://www.googleapis.com/auth/webmasters.readonly.
var clientId = 'YOUR CLIENT ID';
var apiKey = 'YOUR API KEY';
var scopes = 'https://www.googleapis.com/auth/webmasters';
function auth() {
// Set the API key.
gapi.client.setApiKey(apiKey);
// Start the auth process using our client ID & the required scopes.
gapi.auth2.init({
client_id: clientId,
scope: scopes
})
.then(function () {
// We're authenticated, let's go...
// Load the webmasters API, then query the API
gapi.client.load('webmasters', 'v3')
.then(retrieveSearchesByQuery);
});
}
// Load the API client and auth library
gapi.load('client:auth2', auth);
At this point, your retrieveSearchesByQuery function will need to be modified since it doesn't need to get a token by argument anymore in order to pass it in the query. The JavaScript client library should include it in the request automatically.
You can also use the API Explorer to check what parameters are supported for a specific query and check the associated request.
If you need to use an externally generated access token, which should be the case with a Service Account, you need to use the gapi.auth.setToken method to sets the OAuth 2.0 token object yourself for the application:
gapi.auth.setToken(token_Object);
I'm trying to exchange my Dropbox oauth code for a token as per the http api documentation.
When I perform the command with curl thusly:
curl https://api.dropbox.com/1/oauth2/token \
-d code=<authorization code> \
-d grant_type=authorization_code \
-u <app key>:<app secret>
everything works fine, and I am returned my bearer token. Unfortunately, what
seems to be equivalent code written in node.js with the request module fails.
var request = require("request");
var config = require("./config.json");
request({
url: "https://api.dropboxapi.com/1/oauth2/token",
method: "POST",
auth: {
user: config.client_id,
pass: config.client_secret
},
json: {
code: config.code,
grant_type: "authorization_code"
}
}, function(err, resp, body) {
if (err) throw err;
console.log(body);
});
logs:
{ error_description: 'missing required field "grant_type"',
error: 'invalid_request' }
The docs
say that in the event of a 400 error (which this is), I have:
Bad input parameter. Error message should indicate which one and why.
Though as can be seen from the above code, the grant_type is being
specified.
Notably the docs give a second option to authenticate, though this too fails,
albeit with a different message:
Description (abridged)
Calls to /oauth2/token need to be authenticated using the apps's key and secret. These can either be passed as POST parameters (see parameters below) or via HTTP basic authentication. If basic authentication is used, the app key should be provided as the username, and the app secret should be provided as the password.
Params
code String The code acquired by directing users to /oauth2/authorize?response_type=code.
grant_type String The grant type, which must be authorization_code.
client_id String If credentials are passed in POST parameters, this parameter should be present and should be the app's key (found in the App Console).
client_secret String If credentials are passed in POST parameters, this parameter should be present and should be the app's secret.
redirect_uri String Only used to validate that it matches the original /oauth2/authorize, not used to redirect again.
My attempt at the alternate authentication procedure:
var request = require("request");
var config = require("./config.json");
request({
url: "https://api.dropboxapi.com/1/oauth2/token",
method: "POST",
json: {
code: config.code,
grant_type: "authorization_code",
client_id: config.client_id,
client_secret: config.client_secret
}
}, function(err, resp, body) {
if (err) throw err;
console.log(body);
});
logs:
{ error_description: 'No auth function available for given request',
error: 'invalid_request' }
In case the full response from dropbox for either of my two request attemps would be helpful I posted it on pastebin.
I am not including the redirect_uri as I did not use it as part of the code
flow. This is permitted as per the docs. In any case, I don't have any problems
when ommitting it in the curl command which does succeed.
Considering that my API call succeeds when sent through curl, I'm clearly doing
something wrong with my js request. What can I do to get the bearer token I
expect?
It looks like in your curl command, you're sending a form-encoded POST request (which is what OAuth uses), but in your Node.js code, you're sending a JSON-encoded request.
Try form: { ... } instead of json: { ... }.