This works but is ugly. But I can't find how to make optional keys in a pattern. I am probably missing somehting obvious:
post '/api/users' do
args = JSON.parse(request.body.read, {symbolize_names: true})
case args
in {name: name, email: email, bio: bio, password: password}
User.create(args)
200
in {email: email, bio: bio, password: password}
User.create(args)
200
in {email: email, password: password}
User.create(args)
200
else
400
end
end
Related
I'm getting this error
The request signature we calculated does not match the signature you provided
The Canonical String for this request should have been
The String-to-Sign should have been
I am trying to implement the SP APIs in rails.
I've fetched the access-token from https://api.amazon.com/auth/o2/token endpoint.
And after wards created the temporary session token using Aws::STS::Client.
I used Aws::Sigv4::Signer for signature.
First Step (Access Token)
payload = {
grant_type: 'refresh_token',
client_id: [ClientId],
refresh_token: [RefreshToken],
client_secret: [ClientSecret],
}
headers = {'Content-Type': 'application/json'}
response = HTTParty.post("https://api.amazon.com/auth/o2/token", body: payload.to_json, headers: headers)
access_token = response["access_token"]
Second Step (Create Assume Role Using AWS::STS)
result = sts = Aws::STS::Client.new(
region: "us-east-1",
credentials: Aws::Credentials.new("aws-access-key", "aws-secret-key")
).assume_role({
role_arn: "role_arn",
role_session_name: 'sp-api'
})
enter code here
Third Step (Create Signature )
signer = Aws::Sigv4::Signer.new(
service: 'execute-api',
region: 'us-east-1',
# static credentials
access_key_id: access_key_id,
secret_access_key: secret_access_key,
session_token: session_token
)
signature = signer.sign_request(
http_method: 'GET',
url: 'https://sellingpartnerapi-na.amazon.com/orders/v0/orders/ordersID',
headers: {
'host' => 'sellingpartnerapi-na.amazon.com',
'X-Amz-Access-Token' => access_token,
})
Final Step (To call the API with the Signature Headers)
headers = {
'Content-Type' => 'application/json',
"host" => signature.headers["host"],
"X-Amz-Date" => signature.headers['x-amz-date'],
"X-Amz-Security-Token" => signature.headers["x-amz-security-token"],
"X-Amz-Content-Sha256" => signature.headers["x-amz-content-sha256"],
"Authorization" => signature.headers['authorization']
}
data = HTTParty.send(:get, "https://sellingpartnerapi-na.amazon.com/orders/v0/orders/ordersID", headers: headers)
I have an api generated through go-swagger. I am trying to put in a session check it is not firing as I expected. I followed an example that I found in github but didn't seem to work for me.
My code:
// Applies when the "X-Session-Key" header is set
api.SessionKeyHeaderAuth = func(token string) (interface{}, error) {
// test the token
success := routeHandler.HandleSessionHeaderKey(token)
if success{
return nil, nil
}
//We are pessimistic, if they aren't successful then we return a 401
api.Logger("Access attempt with incorrect api key auth: %s", token)
return nil, errors.New(401, "incorrect api key auth")
}
My Yaml (for the endpoint that I am curling):
/auth/logout:
post:
summary: Logs in the user
consumes:
- application/x-www-form-urlencoded
operationId: authLogoutUser
tags:
- auth
description:
Allow users to log out and their session will be terminated
produces:
- application/json
parameters:
- in: header
name: X-Session-Key
type: string
required: true
- in: header
name: X-Profile-Key
type: string
required: true
responses:
200:
description: Login Success
headers:
ProfileKeyHeader:
type: string
description: The key for the profile data
SessionKeyHeader:
type: string
description: The key for the session data
400:
description: Whether the user is not found or error while login, decided on a generic login failure error
schema:
$ref: 'definitions.yaml#/definitions/Error'
429:
description: Too many requests and being throttled
schema:
$ref: 'definitions.yaml#/definitions/Error'
500:
description: Too many requests and being throttled
schema:
$ref: 'definitions.yaml#/definitions/Error'
Any help to see what I did incorrectly would be appreciated.
So, I was being an idiot...
The issue was that I forgot to add Security to my swagger yaml. Once I did that then my function was getting called.
operationId: authLogoutUser
tags:
- auth
description:
Allow users to log out and their session will be terminated
produces:
- application/json
security:
- SessionKeyHeader: []
I am getting this error when trying to get a new refresh token:
{"error"=>"invalid_request", "error_description"=>"Required parameter
is missing: grant_type"}
Here's the code I'm using to generate the request:
HTTParty.post("https://accounts.google.com/o/oauth2/token",
{
client_id: Figaro.env.google_client_id,
client_secret: Figaro.env.google_client_secret,
refresh_token: Figaro.env.google_client_refresh_token,
grant_type: "refresh_token"
})
Despite including the grant_type param, I'm still getting the error. Any ideas why?
Discovered the answer shortly after posting:
HTTParty.post("https://accounts.google.com/o/oauth2/token",
{
:body => {
client_id: Figaro.env.google_client_id,
client_secret: Figaro.env.google_client_secret,
refresh_token: Figaro.env.google_client_refresh_token,
grant_type: "refresh_token"
}
})
Is here any possibility to modify devise SessionsController for ajax communication?
Edit
I found the solution, and posted it into answers, thanks
1. Generate Devise controllers so we can modify it
rails g devise:controllers
Now we have all controllers in the app/controllers/[model] directory
2. Edit routes.rb
Let's set Devise to use our modified SessionsController
First add this code (of course change :users to your devise model) into config/routes.rb
devise_for :users, controllers: {
sessions: 'users/sessions'
}
3. Modify sessions_controller.rb
Find the create method and change it to
def create
resource = User.find_for_database_authentication(email: params[:user][:email])
return invalid_login_attempt unless resource
if resource.valid_password?(params[:user][:password])
sign_in :user, resource
return render nothing: true
end
invalid_login_attempt
end
Create new method after protected
def invalid_login_attempt
set_flash_message(:alert, :invalid)
render json: flash[:alert], status: 401
end
4. devise.rb
Insert this into config/initializers/devise.rb
config.http_authenticatable_on_xhr = false
config.navigational_formats = ["*/*", :html, :json]
5. Invalid email or password message
Insert a new message into config/locales/devise.en.yml under the sessions
invalid: "Invalid email or password."
6. View
= form_for resource, url: session_path(:user), remote: true do |f|
= f.text_field :email
= f.password_field :password
= f.label :remember_me do
Remember me
= f.check_box :remember_me
= f.submit value: 'Sign in'
:javascript
$(document).ready(function() {
//form id
$('#new_user')
.bind('ajax:success', function(evt, data, status, xhr) {
//function called on status: 200 (for ex.)
console.log('success');
})
.bind("ajax:error", function(evt, xhr, status, error) {
//function called on status: 401 or 500 (for ex.)
console.log(xhr.responseText);
});
});
Important thing remote: true
The reason why I am using status 200 or 401 unlike {status: 'true'} is less data size, so it is much faster and cleaner.
Explanation
On signing in, you get these data in params
action: "create"
commit: "Sign in"
controller: "users/sessions"
user: {
email: "test#test.cz"
password: "123"
remember_me: "0"
}
utf8: "✓"
Before signing, you need to authorize the user.
resource = User.find_for_database_authentication(email: params[:user][:email])
User.find_for_database_authentication
If user is found, resource will be filled with something like
created_at: "2015-05-29T12:48:04.000Z"
email: "test#test.cz"
id: 1
updated_at: "2015-06-13T19:56:54.000Z"
Otherwise will be
null
If the user is authenticated, we are about to validate his password
if resource.valid_password?(params[:user][:password])
And finally sign in
sign_in :user, resource
Sources
SessionsController
Helped me
Andreas Lyngstad
I am trying to make a login screen in Ruby Shoes. I am using the ask method to get the username and password but I want the password to show as asterisks. I have to use the secret method but I can't figure out the right syntax..
button "Login" do
username = ask("Enter Username: ")
password = ask("Enter Password: ") :secret => true
end
Should it be done this way?
password = ask("Enter Password: "), secret: true
I tried this too. It doesn't seem to work
Thanks!
Try it this way
button "Login" do
username = ask("Enter Username: ")
password = ask("Enter Password: ", :secret => true)
end