I'm tring to authenticate user to have access to page from extJS. I saw some examples how to do it, but I'm still getting 'authentication required' error. How should I do it?
Here's my code:
Ext.onReady(function() {
var auth = "Basic " + 'user' + ':' + 'password';
// Create store
var myStore = new Ext.data.JsonStore({
// Load data at once
autoLoad: true,
// Override default http proxy settings
proxy: new Ext.data.ScriptTagProxy({
// Call web service method using GET syntax
url: 'http://myotherdomain.com/something.xml',
headers : { Authorization : auth }
})
});
});
Trouble was caused because phrase login:password wasn't encoded, there was sended pure string. When I encoded it with Base64 authentication was accepted.
Related
I am trying to use OAuth2 to authenticate with Twitter on my React-Native/Expo app, using the expo-auth-session package (Expo's guide for Twitter OAuth).
The Twitter OAuth2 flow works in two steps : first the user authorizes the app to access their account, which returns a code, then we exchange that code for an access token.
I am stuck at the second step.
Whenever I try to exchange the code for a token, using expo's exchangeCodeAsync function with these parameters :
exchangeCodeAsync({
clientId: '<CLIENT_ID>',
redirectUri: makeRedirectUri({
scheme: 'my.app',
useProxy
}),
code: response.params.code,
extraParams: {
client_id: "<CLIENT_ID>",
code_verifier: request?.codeVerifier || '',
redirect_uri: makeRedirectUri({
scheme: 'my.app',
useProxy
}),
grant_type: "authorization_code",
},
}, discovery)
I get this error :
Possible Unhandled Promise Rejection (id: 0):
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
What I understand is that the function makes a request to the /oauth2/token route of the Twitter API under the hood, but because of some wrong parameter it returns an HTML error code :
Something went wrong, but don’t fret — let’s give it another shot.
Since the error message is so vague, I have no idea of what is wrong with my request.
I assume that since I have completed the authorization step, the redirect_uri is properly configured. I have also made sure that the format for the "code_verifier" and "code" fields were valid, according to Twitter's documentation.
Here is an Expo Snack to show the complete App.js setup I am using (I've also configured app.json with a custom scheme )
https://snack.expo.dev/lWYp82Pwq
I was able to get a working Twitter login using a bit of a cobbled-together code path:
const twitterDiscovery = {
authorizationEndpoint: "https://twitter.com/i/oauth2/authorize",
tokenEndpoint: "https://api.twitter.com/2/oauth2/token",
}
...
const redirectUri = AuthSession.makeRedirectUri({
scheme: APP_URI_SCHEME,
useProxy: true,
})
const reqConfig = {
clientId: TWITTER_CLIENT_ID,
redirectUri,
usePKCE: true,
scopes: twitterScopes,
}
const authReq = new AuthRequest(reqConfig)
const authUrl = await authReq.makeAuthUrlAsync(twitterDiscovery)
const loginResult = await AuthSession.startAsync({ authUrl, returnUrl })
if (loginResult.type !== "success") {
throw new Error("...")
}
const tokenRequest = new AccessTokenRequest({
...reqConfig,
code: loginResult.params.code,
extraParams: {
code_verifier: authReq.codeVerifier,
},
})
const tokenResult = await tokenRequest.performAsync(twitterDiscovery)
This could obviously be cleaned up a bit, but it does appear to be functional, so I wanted to post even though it's not pretty.
I am trying to link to the account :
Here is my google cloud function
var AuthHandler = function() {
this.googleSignIn = googleSignIn;
this.googleSignInCallback = googleSignInCallback;
}
function googleSignIn(req, res, next) {
passport = req._passport.instance;
passport.authenticate('google',{scope: 'https://www.googleapis.com/auth/userinfo.email',
state:"google",response_type:"token"},
function(err, user, info) {
console.log(user);
})(req,res,next);
};
function googleSignInCallback(req, res, next) {
passport = req._passport.instance;
passport.authenticate('google',function(err, user, info) {
if(err) {
return next(err);
}
if(!user) {
return res.redirect('http://localhost:8000');
}
console.log(user._json.token);
// /res.redirect('/');
res.redirect('https://oauth-redirect.googleusercontent.com/r/xxxxxx#access_token=' + user._json.token + '&token_type=bearer&state=google')
})(req,res,next);
};
module.exports = AuthHandler;
In google Action Console :
I have created the implicit flow and gave my authorisation url as follows:
https://[region]-[projectid].cloudfunctions.net/[functionname]/auth/google
Error :
this is the browser Url
https://assistant.google.com/services/auth/handoffs/auth/complete?state=xxxx&code=xxxxxx
on which the following error is displayed
The parameter "state" must be set in the query string.
Update 1
Before starting this implementation , i have followed this Solution to create the Authentication.
Problems in this Approach :
1.As stated in the Documentation it is not redirecting to google.com and i'm unable to access the token using the APIAI SDK in javascript. but still i can see the Access token in emulator . for better understanding adding images
Here is my simulator O/P
{
"response": {
"debug": {
"agentToAssistantDebug": {
"assistantToAgentDebug": {
"assistantToAgentJson": "{"accessToken\":\"xxxxxx\""
}
},
"errors": []
}
Update 2 :
So i have started creating with implicit flow and here is my complete repo
After battling with it i have achieved it , as there is no proper articles about creation of own Oauth Server that implements the Google Action , this might helpful for future users.
Authorization Endpoint
app.get('/authorise', function(req, res) {
req.headers.Authorization = 'Bearer xxxxxxxxxxx';
// with your own mechanism after successful
//login you need to create a access token for the generation of
//authorization code and append it to this header;
var request = new Request(req);
var response = new Response(res);
oauth.authorize(request, response).then(function(success) {
// https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID?
//code=AUTHORIZATION_CODE&state=STATE_STRING
var toredirect = success.redirectUri +"?code="+success.code
+"&state="+request.query.state ;
return res.redirect(toredirect);
}).catch(function(err){
res.status(err.code || 500).json(err)
}) });
Token Endpoint :
app.all('/oauth/token', function(req,res,next){
var request = new Request(req);
var response = new Response(res);
oauth
.token(request,response)
.then(function(token) {
// Todo: remove unnecessary values in response
return res.json(token)
}).catch(function(err){
return res.status(500).json(err)
})
});
After creation of this endpoints publish to the Google Cloud functions . I have used MYSQL as the DB using SEQUELIZE and Oauth-Server , if anyone need those models , will share it through repo .
With this you can able to link account using your own Server which implements
Auth tokens and Access Tokens
I think the problem is that the URL on this line isn't sending the parameters as query parameters, they're sending them as part of the anchor:
res.redirect('https://oauth-redirect.googleusercontent.com/r/xxxxxx#access_token=' + user._json.token + '&token_type=bearer&state=google')
You should replace the # with a ?, as illustrated here:
res.redirect('https://oauth-redirect.googleusercontent.com/r/xxxxxx?access_token=' + user._json.token + '&token_type=bearer&state=google')
I cannot count how many times I sweared on CORS.
Right now we are trying to access the outlook API to send emails and stuff. We follow the tutorial, do everything on Postman and that works. Now we want to implement it in our Angular 2 application with the following code:
requestAccessToken(code: string)
{
if (code) {
var headers = new Headers();
headers.append("Content-Type", 'application/x-www-form-urlencoded');
var requestoptions = new RequestOptions({
headers: headers,
withCredentials: false // tried true too
})
let body = `grant_type=authorization_code&
redirect_uri=http://localhost:4200&
code=`+ code + `&
client_id=4e...ab&
client_secret=CE.....BC`
this.http.post("https://login.microsoftonline.com/common/oauth2/v2.0/token", body, requestoptions).subscribe((data) =>
{
console.log("data: " + data);
},
error =>
{
console.log("error: " + error);
});
}
}
Our response looks like this:
{
"token_type":"Bearer",
"scope":"calendars.read calendars.read.shared calendars.readwrite calendars.readwrite.shared contacts.read
contacts.read.shared mail.read
user.read",
"expires_in":3599,"ext_expires_in":0,
"access_token":"ey...NjQ",
"refresh_token":"OAQABAAA...Fd8JA"
}
Which is exactly but I want, but however I cannot extract the token out of it and my browser logs the following:
As you can see, the error is logged and not the data and Chrome complains about CORS. I'm really stuck and the only thing the internet says is to change server settings, which is of course not possible with the URL login.microsoftonline.com
I'm trying to implement swagger into my Asp.Net Web API, and i'm running into a problem.
I'm using the password resource owner flow, and i'm having to add a work around in order to do this, which is covered in the following stack overflow question :-
Swagger/Swashbuckle: OAuth2 with Resource Owner Password Credentials Grant
I've got everything working, the Bearer token is added via javascript to the request header in the current browser window, but the api calls to the controller methods requiring authorization are still return "401 - Authorization Failed".
Here is the JavaScript that gets the bearer token and adds the header :-
$('#input_apiKey').change(function () {
var key = $('#input_apiKey')[0].value;
var credentials = key.split(':'); //username:password expected
$.ajax({
url: "http://localhost:42291/token",
type: "post",
contenttype: 'x-www-form-urlencoded',
data: "grant_type=password&username=" + credentials[0] + "&password=" + credentials[1],
success: function (response) {
var bearerToken = 'Bearer ' + response.access_token;
window.swaggerUi.api.clientAuthorizations.add('Authorization', new window.SwaggerClient.ApiKeyAuthorization('Authorization', bearerToken, 'header'));
window.swaggerUi.api.clientAuthorizations.remove('api_key');
alert("Login Succesfull!");
},
error: function (xhr, ajaxoptions, thrownerror) {
alert("Login failed!");
}
});
});
The Curl in the response in Swagger is :-
curl -X GET --header "Accept: application/json" --header
"Authorization: Bearer
NqlSG-WyTx2zkYE8xFklGyZWlQDZdsCKZBHruEXvX47N7PAzw4-jZ4eH5D0yFzQTXj13RwKFFt1rUZt2fzWj1vR5UR87wdlKC3YvsTojYV4-3DsWwY7qYRfiKPuM0j09c3X5lnrtlBVJ1rBRUH0TLjfw_yGxgoLBwOJl9xyC1YWNoPOe2nzL4lMOHodAnMem0IBMJmUo3Rt575tnWAbBsQXWhlImDIxCZXvkZdJtlXfIfBSUdY9gfRWL0ZjKbf7m2-yLzH0gpMAMuKaADmJlIudJc0d4SP1Nn2Kh2HuVH8CX4QgZuu4egl9N6rY2smorP2vBSC4_dC4CpmYYzOTu2wUnUhHDY2Q6NWl377ijDKwZLcW9jtD-2tBiEGmFuRV0mVGnh0zc4w9Ao9jPCdtrbSyGitgloBW-UG2bfyao3eE"
"http://localhost:42291/api/v1/claims"
I cant see anything wrong with this at all.
I've then used Postman to call the exact same URL call, using the same access token that was generated in the javascript call...
Guess what... it works fine.
EDIT
I've tried removing the authorization attribute from the controller, so that i can check the request as it hits the controller method.
looking in the request headers, the Authorization property is null.
Not sure why this is. the CURL suggests its been placed into the request.
EDIT 2
Ive included my Security Definitions:-
"securityDefinitions": {
"oauth2": {
"type": "oauth2",
"description": "OAuth2 Password Grant",
"flow": "password",
"tokenUrl": "http://localhost:42291/token",
"scopes": {}
}
}
EDIT 3
The cURL displayed in the Swagger UI for this api call, when exposed through cURL directly at the command line works without issue.
Now I'm completely confused.
I've managed to correct the problem. It was a simple type mismatch that has caused me days of grief.
In the onComplete.JS, i needed to create a key that matches the key presented in the swagger specification.
If you examine my code snippets above you will see that i created a key and called it "Authorization". But that does not match the named security definition "oauth2".
The working code :-
$('#input_apiKey').change(function () {
var key = $('#input_apiKey')[0].value;
var credentials = key.split(':');
$.ajax({
url: "http://localhost:42291/token",
type: "post",
contenttype: 'x-www-form-urlencoded',
data: "grant_type=password&username=" + credentials[0] + "&password=" + credentials[1],
success: function (response) {
var bearerToken = "Bearer " + response.access_token;
window.swaggerUi.api.clientAuthorizations.remove('api_key');
var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("Authorization", bearerToken, "header");
window.swaggerUi.api.clientAuthorizations.add('oauth2', apiKeyAuth);
alert("Login Succesfull!");
},
error: function (xhr, ajaxoptions, thrownerror) {
alert("Login failed!");
}
});
});
Just to explain this a bit further, you need to create an implementation of IOperationFilter so that swagger can determine which methods of the api require Authorizaion. When you have configured this correctly, you should see a security definition against each api call in the swagger specification :-
My implementation of IOperationFilter :-
public class AssignOAuth2SecurityRequirements : IOperationFilter
{
/// <summary>
/// Apply Security Measures.
/// </summary>
/// <param name="operation"></param>
/// <param name="schemaRegistry"></param>
/// <param name="apiDescription"></param>
/// <exception cref="NotImplementedException"></exception>
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
// Determine if the operation has the Authorize attribute
var authorizeAttributes = apiDescription.ActionDescriptor.GetCustomAttributes<AuthorizeAttribute>();
if (!authorizeAttributes.Any())
return;
// Initialize the operation.security property
if (operation.security == null)
operation.security = new List<IDictionary<string, IEnumerable<string>>>();
// Add the appropriate security definition to the operation
var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
{
{ "oauth2", Enumerable.Empty<string>() }
};
operation.security.Add(oAuthRequirements);
}
}
The authorization mechanism expects that each operation has a security assigned to it. If not present, the header won't be sent. Please share your spec file if you think it's properly assigned
I'm trying to setup a simple Ember.js app to talk with a custom API server, with JWT authentication.
I can login at the API server and obtain a JWT token, but then no Authorization header is set in subsequent calls to the API server.
My login controller is:
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
authenticate: function() {
var credentials = this.getProperties('identification', 'password'),
authenticator = 'simple-auth-authenticator:jwt';
this.get('session').authenticate(authenticator, credentials).then(function() {
// authentication was successful
console.log('OK');
}, function(err) {
// authentication failed
console.log('FAIL ' + JSON.stringify(err));
});
},
logOut: function() {
this.get('session').invalidate();
}
}
});
I can successfully login and obtain a token. My login route:
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
sessionAuthenticationFailed: function(error) {
console.log('Login error: ' + error.ErrorDesc);
this.controllerFor('login').set('loginErrorMessage', error.ErrorDesc);
this.controllerFor('login').set('ErrorMoreInfo', error.MoreInfo);
},
sessionAuthenticationSucceeded: function() {
console.log('Session authenticated: ' + this.get('session').content.secure.token);
// redirect to last route requested, or to default route
var attemptedTransition = this.get('session').get('attemptedTransition');
if (attemptedTransition) {
attemptedTransition.retry();
this.get('session').set('attemptedTransition', null);
} else {
this.transitionTo('index');
}
}
}
});
...shows me the token is properly acquired, and correctly redirects me to my protected routes (e.g. index). Since then, if I try to get any data from the API server, it does not receive any "Authorization: Bearer [token]" header at all.
My environment configuration:
ENV['simple-auth'] = {
authorizer: 'simple-auth-authorizer:token'
};
ENV['simple-auth-token'] = {
refreshAccessTokens: true,
timeFactor: 1000,
refreshLeeway: 300, // Refresh the token 5 minutes (300s) before it expires.
serverTokenEndpoint: 'https://localhost:8000/login',
crossOriginWhitelist:[
'http://localhost:4200',
'https://localhost:8000'
],
identificationField: 'user',
passwordField: 'password',
tokenPropertyName: 'token',
authorizationPrefix: 'Bearer ',
authorizationHeaderName: 'Authorization',
// headers: {},
};
I also tried manually setting the header by calling jqXHR.setRequestHeader overriding the authorize function in my login route, but with no success:
authorize: function(jqXHR, requestOptions) {
var auth= "Bearer " + this.get('session').content.secure.Token;
console.log('Add authorization header ' + auth);
console.log( JSON.stringify(requestOptions));
jqXHR.setRequestHeader("Authorization", auth);
}
Can anybody tell what I'm missing? Shouldn't simple-auth-token take care of adding the header automatically?
Thanks for any help,
al.
I had the same issue, with a REST adapter making calls on a different port.
Solved adding
ENV['simple-auth'] = {
crossOriginWhitelist: ['*']
}
Xabi's answer is working for me. But I didn't find it intuitive.
"Authorized requests" comply to a restrictive CORS policy : the authorization is not added in case of CORS issue.
In the docs :
Ember Simple Auth will never authorize requests going to a different origin than the one the Ember.js application was loaded from.
But requests that don't need an authorizer (with no 'Authorization' header in case of JWT) are allowed and working fine.