laravel jetstream request api route middleware protected api:sanctum return unauthenticated response - laravel-sanctum

I have a problem with 'domain' => env ('SESSION_DOMAIN', null) in the session.php file. When set SESSION_DOMAIN value in .env file, for example
SESSION_DOMAIN=mysite.test
login don't works and there seems to be a middlaware.
If not set this parameter, login work fine, therefore when I call api protected route with sanctum maiddleware ex.
Route::middleware(['auth:sanctum'])->group(function () {
Route::get('/myroute', function () {
return 'hello world!';
});
});
I have unauthenticated response.
If use web.php file route and insert the same function:
Route::middleware(['auth:sanctum'])->group(function () {
Route::get('/api/myroute', function () {
return 'hello world!';
});
});
with api prefix, its works fines.
I followed laravel 8.x sanctum documentation https://laravel.com/docs/8.x/sanctum. In laravel projects 7.* without jetstream I had no problem.
There's any suggest or explaination for this phenomenon.
Any explanation would be helpful for me! Many Thanks.

I ran into a similar issue where I could not authenticate any API request from my frontend. Turns out the generated Kernel.php did not include the Sanctum middleware for session cookies by default - you have to add it manually in your app/Http/Kernel.php:
'api' => [
EnsureFrontendRequestsAreStateful::class, // <- Add and import this middleware
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
After doing this API requests from my frontend are working again. Maybe this resolves your issue as well.

Related

Can login or register only with Firefox using Sanctum API authentication (CSRF token mismatch)

I am developing an SPA with Laravel 9, Vuejs 3 and Sanctum. I am newbie to vue and to Sanctum and I use the sanctum API authentication instead of the token authentication.
At this stage I am in dev and run the embedded laravel server for laravel app and vite server for SPA.
Everything is going smoothly when I sign in and out using the Firefox browser. But when I use Google Chrome or other browser based upon chrome (Brave, Vivaldi, chromium) I cannot sign in nor register. I get a CSRF token mismatch response.
Here are my login an register methods from vuex 's store
actions: {
async register({ commit }, form) {
console.log("in register of index");
await axiosClient.get("/sanctum/csrf-cookie");
return axiosClient.post("/api/register", form).then(({ data }) => {
console.log("data dans index");
console.log(data);
return data;
});
},
async login({ commit }, user) {
await axiosClient.get("/sanctum/csrf-cookie");
return axiosClient
.post("/api/login", user)
.then(({ data }) => {
commit("SET_USER", data);
commit("SET_AUTHENTICATED", true);
//commit("setAuth", true);
return data;
})
.catch(({ response: { data } }) => {
commit("SET_USER", {});
commit("SET_AUTHENTICATED", false);
});
},
Could somebody help me making out what is wrong or missing?
Edited after Suben's response
I read from somebody that the trouble in Chrome could come from the domain being localhost instead of http://localhost in sanctum config.
Thus I did that and could manage to login with both browser. The trouble is that even with a satisfactory answer to login and the reception of the csrf-token now in both browser the store state is not set despite the answer in the .then function being a valid user object.
Moreover, doing 3 similar requests after that strange situation, the 3 of them being under the auth:sanctum middleware, the first failed with csrf-token mismatch, the second succeeded and the third failed also with csrf-token mismatch. Looking at the requests, they have exactly the same 3 cookies including one with the csrf-token.
My guess is, that RESTful APIs are stateless. That means, they do not worry about sessions. https://restfulapi.net/statelessness/
As per the REST (REpresentational “State” Transfer) architecture, the server does not store any state about the client session on the server-side. This restriction is called Statelessness.
When you login a user with Laravel's SPA authentication, then you ARE storing client session data on the server-side.
So you have two options:
You are moving the endpoint /api/login to web.php (logout too!) OR...
You are using the API token based login.
EDIT:
I had my problems at first too with Laravel Sanctums SPA authentication and Vue. There is a video, which goes through a lot of cases, that might help you aswell for the future (Configuration of cors.php and more): https://www.youtube.com/watch?v=It2by1dL50I

Accessing network responses in Cypress.io

I'm working on testing an OpenID Connect service, using Code and Implicit Flow. I would really like to be able to access the messages I get back from the service, especially the 303 See Other message which has the ID Token.
If someone can advise on how to get to response messages I would really appreciate it. Since the services exposes a HTML login page what happens is a
cy.get("#loginButton").click()
so I don't send a cy.request() and that is because I want to test login using the front-end.
You should leverage cy.route, how it works:
before cy.visit you need to add cy.server(), it allows Cypress to intercept every request
you add an alias to the login request
cy.route({
method: "POST",
url: '/auth/token' // this is just an example, replace it with a part of the real URL called to log in the user
}).as("route_login"); // that's the alias, we'll use in soon
right after the cy.get("#loginButton").click() command, you can wait for the login request to happen
cy.wait("#route_login").then(xhr => {
// you can read the full response from `xhr.response.body`
cy.log(JSON.stringify(xhr.response.body));
});
your final test should be something like
it("Test description", () => {
cy.server();
cy.visit("YOUR_PAGE_URL");
cy.route({
method: "POST",
url: '/auth/token'
}).as("route_login");
cy.get("#loginButton").click();
cy.wait("#route_login").then(xhr => {
// you can read the full response from `xhr.response.body`
cy.log(JSON.stringify(xhr.response.body));
});
});
Let me know if you need more help 😉
cy.server() and cy.route() are deprecated in Cypress 6.x
Use cy.intercept() instead:
cy.intercept('POST', '/organization', (req) => {
expect(req.body).to.include('Acme Company')
})
Your tests can intercept, modify and wait on any type of HTTP request originating from your app.
Docs: https://docs.cypress.io/api/commands/intercept.html (with examples)

Connecting to github with Ember.js and Torii (oauth2)

I'm trying to use the github-oauth2 provider in Torii, but I'm stumped on how I'm supposed to se tup some of the callbacks. I'll trace the code I'm using, as well as my understanding of it, and hopefully that can help pinpoint where I'm going wrong.
First, in my action, I'm calling torii's open method as it says to do in the docs:
this.get('torii').open('github-oauth2').then((data) => {
this.transitionTo('dashboard')
})
And, of course, I have the following setup in my config/environment.js:
var ENV = {
torii: {
// a 'session' property will be injected on routes and controllers
sessionServiceName: 'session',
providers: {
'github-oauth2': {
apiKey: 'my key',
redirectUri: 'http://127.0.0.1:3000/github_auth'
}
}
},
}
The redirectUri is for my Rails server. I have the same redirectUri setup on my github app, so they match.
Here's what I have on my server. It's likely this is where the problem is. I'll get to the symptoms at the end.
def github
client_id = 'my id'
client_secret = 'my secret'
code = params[:code]
#result = HTTParty.post("https://github.com/login/oauth/access_token?client_id=#{client_id}&client_secret=#{client_secret}&code=#{code}")
#access_token = #result.parsed_response.split('&')[0].split('=')[1]
render json: {access_token: #access_token}
end
So I post to github's access_token endpoint, as I'm supposed to, and I get back a result with an access token. Then I package up that access token as json.
The result of this is that the torii popup goes to the rails page:
Unfortunately, what I was hoping for was for the torii popup to disappear, give my app the access_token, and for the code to move on and execute the code in my then block.
Where am I going wrong?
Many thanks to Kevin Pfefferle, who helped me solve this and shared the code to his app (gitzoom) where he had implemented a solution.
So the first fix is to clear my redirectUri, and to set it on github to localhost:4200. This made the app redirect so that it's an Ember app that it's redirected to.
The second fix was to create a custom torii provider
//app/torii-providers/github.js
import Ember from 'ember';
import GitHubOauth2Provider from 'torii/providers/github-oauth2';
export default GitHubOauth2Provider.extend({
ajax: Ember.inject.service(),
fetch(data) {
return data;
},
open() {
return this._super().then((toriiData) => {
const authCode = toriiData.authorizationCode;
const serverUrl = `/github_auth?code=${authCode}`;
return this.get('ajax').request(serverUrl)
.then((data) => {
toriiData.accessToken = data.token;
return toriiData;
});
});
}
});
Not sure why this then triggers but the then I was using before didn't. Anyways, it grabs the data and returns it, and then the promise I was using before gets the data correctly.
this.get('torii').open('github-oauth2').then((data) => {
//do signon stuff with the data here
this.transitionTo('dashboard')
})
So there we go! Hopefully this helps other folks who are stuck in the future.

swagger-tools on node: how to serve swagger-ui from basePath

using nodejs and swagger-tools v0.8.7 to route endpoints.
"basePath": "/api/myapi" in the api/myapi.json works great, ie: GET, POST, etc... at http://localhost:3000/api/myapi works.
But I still have to access http://localhost:3000/docs/ to get at the UI tool. How can I serve this from http://localhost:3000/api/myapi/docs/ ?
Same question for serving the yaml at /api/myapy/api-docs instead of /api-docs.
Thx.
got what i wanted via:
app.use(middleware.swaggerRouter(
{
swaggerUi: '/myapi.json',
controllers: './lib'
}));
app.use(middleware.swaggerUi(
{
"apiDocs": "/myapi/api",
"swaggerUi": "/myapi.json"
}
));

Twitter O-Auth Callback url

I am having a problem with Twitter's oauth authentication and using a callback url.
I am coding in php and using the sample code referenced by the twitter wiki, http://github.com/abraham/twitteroauth
I got that code, and tried a simple test and it worked nicely. However I want to programatically specify the callback url, and the example did not support that.
So I quickly modified the getRequestToken() method to take in a parameter and now it looks like this:
function getRequestToken($params = array()) {
$r = $this->oAuthRequest($this->requestTokenURL(), $params);
$token = $this->oAuthParseResponse($r);
$this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
return $token;
}
and my call looks like this
$tok = $to->getRequestToken(array('oauth_callback' => 'http://127.0.0.1/twitter_prompt/index.php'));
This is the only change I made, and the redirect works like a charm, however I am getting an error when I then try and use my newly granted access to try and make a call. I get a "Could not authenticate you" error. Also the application never actually gets added to the users authorized connections.
Now I read the specs and I thought all I had to do was specify the parameter when getting the request token. Could someone a little more seasoned in oauth and twitter possibly give me a hand? Thank You
I think this is fixed by twitter by now or you might have missed to provide a default callback url in your application settings, which is required for dynamic callback url to work as mentioned by others above.
Any case, I got this working by passing the oath_callback parameter while retrieving the request token. I am using twitter-async PHP library and had to make a small tweak to make the library pass the callback url.
If you are using twitter-async, the change is below:
modified getRequestToken and getAuthenticateURL functions to take callback url as parameter
public function getRequestToken($callback_url = null)
{
$params = empty($callback_url) ? null : array('oauth_callback'=>$callback_url);
$resp = $this->httpRequest('GET', $this->requestTokenUrl, $params);
return new EpiOAuthResponse($resp);
}
public function getAuthenticateUrl($callback_url = null)
{
$token = $this->getRequestToken($callback_url);
return $this->authenticateUrl . '?oauth_token=' . $token->oauth_token;
}
And pass the callback url from your PHP code.
$twitterObj->getAuthenticateUrl('http://localhost/twitter/confirm.php');
#Ian, twitter now allows 127.0.0.1 and has made some other recent changes.
#jtymann, check my answer here and see if it helps
Twitter oauth_callback parameter being ignored!
GL
jingles
even me to was getting 401 error.. but its resolved..
during registering your application to twitter you need to give callback url...
like http://localhost:8080.
i have done this using java...
so my code is: String CallbackURL="http://localhost:8080/tweetproj/index.jsp";
provider.retrieveRequestToken(consumer,CallbackURL);
where tweetproj is my project name
and index.jsp is just one jsp page...
Hope this may helps u...
After the user authorizes the application on twitter.com and they return to your callback URL you have to exchange the request token for an access token.
Twitter does not honor the oauth_callback parameter and will only use the one specified in the registered application settings.
It also doesn't allow for 127.0.0.1 or localhost names in that callback, so I've setup http://dev.twipler.com which is setup for 127.0.0.1 in DNS so you can safely use;
http://dev.twipler.com/twitter_prompt/index.php

Resources