Am working on LTI Tool Provider, I have implemented an LTI auth package and am successfully able to get two (..one?) legged OAuth working aka match the signatures and we're all good to redirect, except one important thing.
What I want to be able to do, is
If this user doesnt exist, create it and log in
If the user exists, log our user in
Right now I have no way of actually determining my user once I redirect to a client route.
The LTI Consumer points to my Iron Router server route that looks something like:
Router.route('/lti', { where: 'server' }).post(function() {
provider.valid_request(request, function(error, valid) {
if (valid) {
this.response.writeHead(302, { Location: '/' });
} else {
this.response.writeHead(403);
}
});
return this.response.end();
});
Are there any packages I can use to get this working simply? Can I use something like accounts-base? Do I need to implement my own logic?
Any help or direction is appreciated.
Cheers.
I solved this by implementing a single-use authentication token system, handled by a custom login handler using accounts-base and the Accounts.registerLoginHandler method.
Rough auth flow overview:
LTI Route (server)
If authenticated, create a new account/update the old one
Insert a token + timestamp object into a collection.
Redirect to an authentication route, passing our token as a parameter
Auth route (client)
Check if our user is logged in. If so, redirect to our home route
If a token has been provided and it exists, mark it used. As we have no way of checking for a user in a server route, if a user has a session, closed and opens the link through the LMS again, we need to deal with our excess tokens.
If our user is not logged in, check for a token. If it exists, pass it to a custom authentication via Accounts.callLoginMethod
Our custom login handler validates our token. If legitimate, consume the token and log the user in.
My code is messy, but when I refactor I'll probably open source it as a Meteor package.
Related
I'm pretty new to FastAPI and OAuth2 in general. I just worked through the tutorial "Simple OAuth2 with Password and Bearer" and it mostly made sense, but there was one step that felt like magic to me..
How does the access token get stored onto the client and subsequently get passed into the client's requests?
My understanding of the flow is that it's basically
User authenticates with their username and password (these get POST'ed to the /token endpoint).
User's credentials are validated, and the /token endpoint returns the access token (johndoe) inside some JSON. (This is how the user receives his access token)
???
User make a subsequent request to a private endpoint, like GET /users/me. The user's request includes the header Authorization: Bearer johndoe. (I don't think the docs mention this, but it's what I've gathered from inspecting the request in Chrome Developer Tools)
The authorization token is then used to lookup the user who made the request in (4)
Step (3) is the part that I don't understand. How does the access token seemingly get stored on the client, and then passed as a header into the next request?
Demo
When you run the code in the tutorial, you get the following swagger docs. (Note the Authorize button.)
I click Authorize and enter my credentials. (username: johndoe, password: secret)
And now I can access the /users/me endpoint.
Notice how the header Authorization: Bearer johndoe was automagically included in my request.
Last notes:
I've checked my cookies, session storage, and local storage and all are empty
The authorization header disappears if I refresh the page or open a new tab
I suspect Swagger is doing something under the hood here, but I can't put my finger on it.
If you need persistence for the token you'd usually use localStorage or similar, but in SwaggerUIs specific case, the authentication information is kept internally in the library.
If you have enabled persistence SwaggerUI will persistent the access token to localStorage:
export const persistAuthorizationIfNeeded = () => ( { authSelectors, getConfigs } ) => {
const configs = getConfigs()
if (configs.persistAuthorization)
{
const authorized = authSelectors.authorized()
localStorage.setItem("authorized", JSON.stringify(authorized.toJS()))
}
}
I have a web app and I am using firebase authentication to login/signup our users.
In the past I have used Passport for login in my app which works but you have to maintain your own database and security blah blah... but I can control when my user can visit a page after logging via Passport using middleware like this -
// isAuthentcated is my middleware on server side.
app.get('/home', isAuthenticated,(req,res)=>{
res.render('home');
});
How can I do the same using firebase because there isn't any mechanism to do that. I have read different answers on stackoverflow and most of the pople are suggesting something like below which obviously isn't secure. Anybody can just type home.html and get to the page.
firebase.auth().onAuthStateChanged(user => {
if(user) {
window.location = 'home.html'; //After successful login, user will be redirected to home.html
}
});
Although, I have thought of using firebase-admin sdk token verification and try to follow the suggestion here but I don't know how it can be useful to do that on server side. Do you guys have any suggestions? How do you redirect user to a new page. An ajax post/get request from a client to a route '/home' with a header containing 'Bearer token' just validate the token but doesn't redirect user because it is a ajax call which is meant for updating a portion of a page.
Now, the question really is, Is it even possible to do that with firebase authentication?
If you host your site on App Engine you can send the ID token of the client with the request for the HTML. This could take the form of a cookie, a parameter, or whatever you choose to securely transfer the token from client to server.
Then the server can use the Firebase Admin SDK to verify the ID token, and use whatever logic you need to determine whether the request is authorized.
Context:
I've implemented OpenIddict in my application, basing on GitHub readme. I currently use TokenEndpoint to log user in.
services.AddOpenIddict<ApplicationUser, UsersDbContext>().EnableTokenEndpoint("/api/Account/Login")
Although calling /api/Account/Info works and it returns token in response, I need to get some basic data about logged in user (username, email, account type). Response from token endpoint doesn't provide that.
I've found something like UserinfoEndpoint:
.EnableUserinfoEndpoint("/api/Account/Info")
But what I see after in http response is:
{
"sub": "ea2248b4-a[...]70757de60fd",
"iss": "http://localhost:59381/"
}
This should return me some Claims. As it doesn't return anything, I assume that no Identity Claims were created during token generation.
What I need to know in a nutshell:
Is using Token Endpoint correct way to log in user?
Do I need to generate Claims by myself?
Can I control Claims by myself and how?
How to make some Claims visible through UserInfoEndpoint?
Is using Token Endpoint correct way to log in user?
Yep.
Do I need to generate Claims by myself?
The userinfo endpoint simply exposes the tokens stored in the access token (which is something that may change in the future).
Can I control Claims by myself and how?
How to make some Claims visible through UserInfoEndpoint?
To allow the userinfo endpoint to return more claims, you'll have to request more scopes. Read http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims for more information.
In a future version, we may allow you to return custom claims, but it's not currently supported.
I am using Visual Studio 2015 Enterprise and ASP.NET vNext Beta8 to issue and consume JWT tokens as described here.
In our implementation we're storing some client details in Redis at token issuing time and we would like the flush this information when the user logs out.
My question is what is the best practices for logging out with OIDC?
While I could roll my own contoller for this purpose I couldn't help but notice Open ID Connect (OIDC) seems somewhat primed to handle this case. For example OIDC has an OnLogoutEndpoint handler and LogoutEndpointPath settings. But when I call the OIDC logout URI that handler appears to accept any random x-www-form-urlencoded form I throw at it and doesn't in any particular way seem to be demanding the presence of a token.
Any advice on proper OIDC logout practices would be very much appreciated.
In AspNet.Security.OpenIdConnect.Server, the logic used for the logout endpoint is left as an exercise.
In this sample, it is implemented using an MVC 6 controller, where you're - of course - free to add custom logic to remove cached details from your Redis server.
[HttpPost("~/connect/logout")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout() {
// When invoked, the logout endpoint might receive an unauthenticated request if the server cookie has expired.
// When the client application sends an id_token_hint parameter, the corresponding identity can be retrieved using AuthenticateAsync.
var identity = await HttpContext.Authentication.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);
// Remove the cached details here. If you need to determine
// who's the authenticated user, you can use the identity variable.
// Remove the authentication cookie and return the user to the client application.
return SignOut("ServerCookie", OpenIdConnectServerDefaults.AuthenticationScheme);
}
You can also do something similar directly from the LogoutEndpoint event. Don't forget to call context.HandleResponse() to make sure the request is not intercepted by another middleware.
I have seen the recommended method of
Meteor.users.update({}, {$set: { "services.resume.loginTokens" : [] }});
to logout a user, but that only works when the page is refreshed.
I'm looking for a way that when I remove the user from the database, it logs out the user. I need the following code to force a logout on the client IF the client was logged in for that user. I cannot wait for the user to refresh the page.
Meteor.users.remove({_id: this.userId})
EDIT:
I have verified that this behavior in on my angular pages and not when I'm on a Meteor template. When I am on a Meteor template, it seems to work, but when I move to an angular route it stops behaving as required.
You need to be using something reactive that is tied in to checking who the current user is.
If your using iron router, there is examples of using login mappers to redirect users to login pages when the user is unauthorized.
Something akin to
if(!Meteor.user()) { window.location = '/login'; };
If you delete the user from the users table, that will invalidate and redirect you.
Obviously you would need to have conditions that protect certain areas from invalidating this - but the general idea is in just using reactive variables.