I am using package "github.com/dgrijalva/jwt-go" in golang to authenticate api hits.
The code for creating a jwt token is:
token := jwt.NewWithClaims(jwt.SigningMethodHS256, &jwt.MapClaims{
"email": "test#example.com",
"exp": time.Now().Add(time.Hour * 8760).Unix(),
"role": "customer",
"name": "John Doe",
"ip": 0.0.0.0,
"user_agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0"
"id": 1,
})
tokenString, err := token.SignedString([]byte(config.SignKey))
Following are the steps to use this token:
First login api hits and we call above method to generate token and return this token in the api response.
After that another api hits which contains this token in its headers with "Bearer " string. We decode this token and authenticate it through following code:
bearer := strings.Split(c.Request.Header["Authorization"][0], "Bearer")
bearerToken := strings.TrimSpace(bearer[1])
token, err := jwt.Parse(bearerToken, func(token *jwt.Token) (interface{}, error) {return config.SignKey, nil})
if err != nil {
c.JSON(200, gin.H{"response": "{error: "err", msg: Session Expired. Please log out and back in to continue2.}",})
c.Abort()
return
}
Now suppose the token was decoded for url: http://SOMEDOMAIN.COM/api/v1/SOMEAPI
from this api I issued another curl command in the format:
"curl --header 'Ip: " + ip + "' --header 'User-Agent: " + userAgent + "' --header 'Authorization: " + token + "' 'http://SOMEDOMAIN.COM/api/v2/ANOTHERAPI'"
This command hits another different api but using the same credentials like token is same what was created from login api.
Both apis with different urls are hosted over same server but different golang project folder.
Now at this time this package does not authenticate the token and gives following error:
{"response":{"code":400,"api_status":10,"message":"Session Expired. Please log out and back in to continue2.","data":{"Inner":{},"Errors":4}}}
I was looking for meaning of error code 4 in this case.
Can anyone please explain what is the meaning of Error: 4 and why it is behaving like this on different api urls?
When I investigated your code,
There is an misuse about your config.SignKey , It seems it was casting []byte while signing token.
But while parsing your token;
{return config.SignKey, nil}
You used default type and didn't cast []byte.
{return []byte(config.SignKey), nil}
I think it is the issue.
Related
I'm using Bitbucket Connect App and getting JWT token from webhook event.
When I am using the latest JWT to get access token, the access token API returning blank in response.
API:
curl -X POST -H "Authorization: JWT {jwt_token}" \ https://bitbucket.org/site/oauth2/access_token \ -d grant_type=urn:bitbucket:oauth2:jwt
Example:
curl -X POST -H "Authorization: JWT ey*****XVCJ9.eyJpc3MiOi****asdfQ.**BBD**" \
https://bitbucket.org/site/oauth2/access_token \
-d grant_type=urn:bitbucket:oauth2:jwt
Response
{blank}
API Reference:
https://developer.atlassian.com/cloud/bitbucket/oauth-2/
Thanks
I had the same problem until I added the sub key to the payload. Set the value to the value received in clientKey during the app installation lifeycle event.
I followed this documentation to generate Access Token and it worked.
https://pawelniewiadomski.com/2016/06/06/building-bitbucket-add-on-in-rails-part-7/
Most of the Part for generating access token using Bitbucket Cloud API
def get_access_token
unless current_jwt_auth
raise 'Missing Authentication context'
end
# Expiry for the JWT token is 3 minutes from now
issued_at = Time.now.utc.to_i
expires_at = issued_at + 180
jwt = JWT.encode({
iat: issued_at,
exp: expires_at,
iss: current_jwt_auth.addon_key,
sub: current_jwt_auth.client_key
}, current_jwt_auth.shared_secret)
response = HTTParty.post("#{current_jwt_auth.base_url}/site/oauth2/access_token", {
body: {grant_type: 'urn:bitbucket:oauth2:jwt'},
headers: {
'Content-Type' => 'application/x-www-form-urlencoded',
'Authorization' => 'JWT ' + jwt
}
})
if response.code == 200
Response.new(200, response.parsed_response)
else
Response.new(response.code)
end
end
I am running tests on a web application to test WYSIWYG functionality and XSS vulnerabilities. I use the following command before
beforeEACH(() => {
cy.vaderAuth()
});
Cypress.Commands.add('vaderAuth', () => {
let config = Cypress.config();
cy.request({
method: 'POST',
url: Cypress.config('tokenUrl') + '/api/v1?actions=api/v1/login',
body: {
username: config.horizon.username,
password: config.horizon.password,
}
}).then(response => {
window.localStorage.setItem('JWT', response.body['api/v1/login'].token)
})
})
The above command successfully gets the Bearer Token but then the following test throws a 401 Unauthorised error.
it('Sending a regular API request to Welcome Messages', function() {
cy.request({
method : 'POST',
url : '/api/v1/organisations/welcome-message?actions=api/v1/organisations/welcome-message/set-welcome-messages',
body : {"welcome_messages":[{"message":"<p>Test investor welcome message!</p>","type":"User"},{"message":"<p>Internal User welcome message Cypress Test. </p>","type":"Internal User"},{"message":"<p>Test entrepreneur welcome message!</p>","type":"Entrepreneur"}]},
headers : {"Authorization": "Bearer " + window.localStorage.JWT}
})
})
beforeEach working, API request 401
401 cypress error
I have checked the failure and it is sending the Bearer Token as a header, and the request headers match the headers the same request sends if I enter the Bearer Token manually as follows.
it('Sending a regular API request to Welcome Messages', function() {
cy.request({
method : 'POST',
url : '/api/v1/organisations/welcome-message?actions=api/v1/organisations/welcome-message/set-welcome-messages',
body : {"welcome_messages":[{"message":"<p>Test investor welcome message!</p>","type":"User"},{"message":"<p>Internal User welcome message Cypress Test. </p>","type":"Internal User"},{"message":"<p>Test entrepreneur welcome message!</p>","type":"Entrepreneur"}]},
//headers : {"Authorization": "Bearer (insertbearertokenhere)}
})
})
When entering the Bearer Token manually the following tests all run smoothly with no error, but if I have to go in and change the Bearer Token every time I run these tests, it kind of defeats the point of automating it as by the time I've logged into my web app and got the token, I may as well test the application manually.
Any help on this would be greatly appreciated as I have been working on it with no luck for around a week now.
My iOS app sends RSS subscription requests to superfeedr like so:
func subscribe(feed: String) {
let parameters = ["hub.mode" : "subscribe", "hub.topic" : feed, "format" : "json" , "hub.callback" : "https://AppID:javascript-key=JavascriptKey#api.parse.com/1/functions/superfeedrnew"]
let user = "user"
let token = "token"
let str = "\(user):\(token)"
let utf8str = str.dataUsingEncoding(NSUTF8StringEncoding)
if let base64Encoded = utf8str?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
{
let headers = ["Authorization": "Basic \(base64Encoded)"]
Alamofire.request(.POST, "https://push.superfeedr.com", parameters: parameters, headers: headers)
.responseJSON { response in
debugPrint(response)
}
}
}
The feed registers fine in superfeedr and superfeedr should send a notification to my Parse callback URL which is for now just an hello world function which should at least print the input.
Parse.Cloud.define("superfeedrnew", function(request, response) {
response.success('** WEBHOOK WORKING **' + request);
});
My problem is that the notification is never received/function not executed using this approach and I don't know why. I can however execute the function fine using curl:
curl -X POST \
-H "X-Parse-Application-Id: app ID" \
-H "X-Parse-REST-API-Key: rest key" \
-H "Content-Type: application/json" \
-d '{}' \
https://api.parse.com/1/functions/superfeedrnew
Edit: This is the first time I use webhooks so I've tried this: Update Parse.com User from Stripe Webhook and it works perfectly with stripe. Superfeedr still isn't able to call my cloud code function though. Drives me nuts. I also get a notification delivery failure message on my superfeedr dashboard.
Since you use your superfeedr credentials (login + token) and no hub.verify value, Superfeedr will actually not need to perform a verification of intent.
You can check your Superfeedr subscription list from the website and you will should your subscription.
I need to understand how to authenticate a REST client (could be Paw, could be an android app, an iOs app using AFNetworking with jHipster and I think, more in general, with spring-boot of which I am no expert).
While I am able to obtain a token when logged in a browser, and subsequently use this token in the following requests, I do not understand how I can authenticate in the first place using RESTful best practices.
For example, in Paw.app, I can pass a Basic authentication, or Oauth2, but I don't understand how to get the session token simply authenticating as I do on a web browser.
Similarly, in AFNetworking I am able to pass basic authentication, e.g.
NSString*auth=[NSString stringWithFormat:#"%#:%#", #"admin", #"admin"];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [auth base64EncodedString]];
[manager.requestSerializer setValue:authValue forHTTPHeaderField:#"Authorization"];
But I struggle to understand how to authenticate with the session security which is bundled in jHipster/spring boot.
First of all, do not use HTTP session authentication for mobile apps.
On the other hand, Oauth2 or JWT works fine with mobile apps. The basic idea behind them is to get a token from Jhipster to mobile the token has an expiry time. In that time you can use the token to access any REST API of Jhipster to access data.
Below I am showing the code snippet of how I was using the Jhipster rest API in my angularjs based ionic app. I hope it gives the idea of what you need to do.
uncomment cors in application.yml inside jhipster
cors: #By default CORS are not enabled. Uncomment to enable.
allowed-origins: "*"
allowed-methods: GET, PUT, POST, DELETE, OPTIONS
allowed-headers: "*"
exposed-headers:
allow-credentials: true
max-age: 1800
To access REST API with Oauth2 authentication in ionic you must first get the token in the ionic app by
$http({
method: "post",
url: "http://192.168.0.4:8085/[Your app name]/oauth/token",
data: "username=admin&password=admin&grant_type=password&scope=read write&client_secret=my-secret-token-to-change-in-production&client_id=auth2Sconnectapp",
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'Authorization': 'Basic ' + 'YXV0aDJTY29ubmVjdGFwcDpteS1zZWNyZXQtdG9rZW4tdG8tY2hhbmdlLWluLXByb2R1Y3Rpb24='
}
})
.success(function(data) {
alert("success: " + data);
})
.error(function(data, status) {
alert("ERROR: " + data);
});
Here "YXV0aDJTY29ubmVjdGFwcDpteS1zZWNyZXQtdG9rZW4tdG8tY2hhbmdlLWluLXByb2R1Y3Rpb24=" is equal to (clientId + ":" + clientSecret)--all base64-encoded
The above $http if successful will give you this JSON which contains token and it's expiry time
{
"access_token": "2ce14f67-e91b-411e-89fa-8169e11a1c04",
"token_type": "bearer",
"refresh_token": "37baee3c-f4fe-4340-8997-8d7849821d00",
"expires_in": 525,
"scope": "read write"
}
Take notice of "access_token" and "token_type" if you want to access any API this is what you have to use. We send the token with API to access data until the token expires then we either refresh it or access for a new one.
For example
$http({
method: "get",
url: "http://192.168.0.4:8085/auth-2-sconnect/api/countries",
withCredentials: true,
headers: {
'Authorization':' [token_type] + [space] + [access_token] '
}
})
.success(function(data) {
alert("success: " + data);
})
.error(function(data, status) {
alert("ERROR: " + data);
});
Here a summarisation of how I implemented the solution. It’s real swift code, but please take it as pseudocode, as it might be incorrect.
make a call to whatever method you need to call, passing in such method a callback (block, or equivalent) for the success and one for the failure
func action(
URLString:String,
method:Method,
encoding:Encoding = .JSON,
parameters:[String : AnyObject]?,
success:(statusCode:Int, responseObject:AnyObject)->Void,
failure:(statusCode:Int, error:NSError)->Void
)
Inside the method es. /events you handle a particular case of failure, which is when the status code is 401.
if(r!.statusCode==ResponseCodes.HTTP_UNAUTHORIZED.rawValue){
loginAndAction(URLString, method: method, encoding: encoding, parameters: parameters, success: success, failure: failure)
}else{
failure(statusCode: response.response!.statusCode, error:response.result.error!)
}
In this particular case, instead of returning back the result and calling the failure callback, you call a login() method which, after the necessary parameters, accept the original success() callback
func loginAndAction(
URLString:String,
method:Method,
encoding: Encoding,
parameters:[String:AnyObject]?,
success:(statusCode:Int, responseObject:AnyObject)->Void,
failure:(statusCode:Int, error:NSError)->Void
)->Void
if the authentication succeeds
var d:[String:AnyObject] = response.result.value as! [String:AnyObject]
self.authToken = d["access_token"] as! String
action(URLString, method: method,encoding:encoding, parameters: parameters, success: success, failure: failure)
at this point the method action could use a proper working token.
This should happen only once a day (based on the token expiration), and it is a mechanism appliable to the oauth2 refresh_token call.
I have followed and double checked the steps to get a bearer token from https://dev.twitter.com/oauth/application-only
i keep getting the following error :
Status : 403 Forbidden
{"errors":[{"code":99,"message":"Unable to verify your credentials","label":"authenticity_token_error"}]}
I tried passing grant_type=client_credentials in body as well as query parameter.
The URL i am hitting is : https://api.twitter.com/oauth2/token?grant_type=client_credentials
Headers Set :
Authorization : Basic [base64encoded(client_key:client_secret)]
Content-Type : application/x-www-form-urlencoded;charset=UTF-8
I am using poster as the rest client to make the calls.
Could any one point out where i may be going wrong.
Thanks a lot.
Send "grant_type=client_credentials" as the payload.
var options = {
"method":"post",
"headers": {
"Authorization":"Basic " + Utilities.base64Encode(param),
"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"
},
"payload" : "grant_type=client_credentials"
};
var response = UrlFetchApp.fetch(TOKEN_URL,options);