I am trying to use NextAuth as auth provider for my project. I have a requirement where I have Credential based login/password. In this case when I login I have to pass the username/password to the custom API (for ex.: abc.com/auth/login). This API as success will return me a JWT for future communication to access their resources.
What I understood from NextAuth that it maintain its own session and JWT(if DB not provided). This feature works in my case but I have to maintain the JWT which the API has returned me(mentioned above). So now there are two JWT one which I received from API and the one which NextAuth has created.
My question:
Is there a way which I can use to maintain the custom JWT which I received from API?
Is there a way if API token has been expired to tempered so I can kill NextAuth session.
What is the best way to keep NextAuth Session and Custom JWT token in sync?
Thanks in advance!
Got the answer on Next-auth repo discussions itself.
This solution worked for me.
So, we can let next-auth generate the JWT token which contains the same payload as the one provided by the API (We can disable the token signature verification in the API).
Then update the next-auth configuration to have a save token in cookie has httpOnly: false so we can access the token server and client sides by adding it in the configuration:
const options = {
// ...
cookies: { sessionToken: { name: `next-auth.session-token`, options: { httpOnly: false } } },
}
After that we can use the code to get the JWT token to be passed to the API calls from the server and client sides:
import cookies from 'next-cookies'
import Cookies from 'js-cookie'
// Server-Side
cookies(context)['next-auth.session-token']
// Client-side
Cookies.get('next-auth.session-token')
Now we just need to figured out how to save my JWT token provided by my API instead of using the one generated by next-auth.
Then we will be able to reactivate the signature verification in the backend API.
You can follow the thread here
Related
I'm writing a web frontend in vapor which has a login and signup pages, and an authenticated user area with actions that require being logged in.
There is a seperate instance (also swift vapor) which handles authentication over a rest api (basically there are multiple other things which can authenticate, and from various sources/reasons so made sense to have it as a seperate instance).
The idea is all the authentication is passed on from the webserver to the api
The idea and what I have currently is the web's /login page has a form which sends a /login POST request which talks via the api instance sending a post request (/auth/login). This either succeeds or not. and the webserver responds based on the api response
The issue I have is how I persist that authentication- do I need some custom middleware to store the session token or check the token via the api that I can use on subsequent requests?
I've enabled bearer authentication on the api, and the api's success login reply json object returns the session token that I check in the bearer authorisation.
There's also a vapor-session set cookie returned in the api's login response. I've tried adding that into the web's login response (redirect response to the logged in area) so the browser should send back the session cookie on future requests but I haven't as of yet been able to get this to work. The browser is sending a different value for vapor-session cookie.
Does this sound like a sensible approach?
I'm not sure the best way of going about this
Including some bits of code to help see what I have so far
API instance's routes, I'm sure if I need the session authenticator or not
auth//.grouped(UserDB.sessionAuthenticator())
.grouped(UserAuthenticator())
.grouped(UserDB.guardMiddleware())
.group("")
{ authenticated in
authenticated.get("me", use: getCurrentUser)
This is the UserAuthenticator that supports bearer authentication by looking up the session token in the db. Could I just use the session token in bearer auth header for all requests web -> api? I'm not sure how I'd provide that on each web request- should I be setting a cookie? Is that basically what the vapor-session cookie is?
struct UserAuthenticator: BearerAuthenticator {
typealias User = UserDB
func authenticate(bearer: BearerAuthorization, for request: Request) -> EventLoopFuture<Void> {
let tokenHash = SHA256.hash(bearer.token)
return request.sessionTokens
.find(tokenHash: tokenHash)
.flatMap {
if let sessionToken = $0 {
request.auth.login(sessionToken.user)
}
return request.eventLoop.makeSucceededVoidFuture()
}
}
}
I haven't put any middleware on the authenticated web routes- should I be doing that and checking there? would I do an api request in the middleware authenticate method?
I'm not really sure what the correct approach is here
Assuming your front-end and API are separate you need a custom User type to add to the authenticated session - this is how you know a user is logged in. You probably don't need to store much on the user, just their username and the API token
I have a grails 3 application where authentication is done by Siteminder. After the user is authenticated we should be able to generate a JWT token and using that other rest apis call be protected.
I have used RequestHeaderAuthenticationFilter to authenticate the request header. Can anyone help in integrating JWT token in this scenario.
Thanks is advance
I achieved it by using a custom token generator which is called after the request header authentication and saved the token in http response header. Created a custom rest token validation filter to validate the token in API calls
I use the Postman desktop app for web API testing. I have a lot of controllers and for each need a token. First I get Bearer token and then copy it to other requests. This token have limit time. Can I get token automatically and then automatically set it to all others requests ?
ok, I just used Environments in postman.
1 - create new Environment with token.
2 - add test after auth request like this :
var jsonData = JSON.parse(responseBody);
var token = jsonData._token;
postman.setEnvironmentVariable("token", token);
3 - just set {{token}}
And of course you can set token before request if you use Pre-request Script in one of requests.
Write below code in tests tab in postman for your login request.
if(pm.response.code === 200) {
pm.environment.set('authToken', pm.response.json().token)
}
Then edit your collection and set your env authToken inside.
You can save and re-use the token's using the Token Name from Postman. You can select it from the available token list.
One of the many cases are.
Request for a refresh token using the credentials
Use the refresh token to get an access token
Use the access token to authenticate the API.
The step 1 sometimes requires us to login to an interface of the API provider and get an authentication code to our callback url. Some API provider's allow us to override this by providing the client_secret key and the client_id as an authorization header and the refresh token as the request parameters and by setting prompt as none.
From the documentation.
prompt (optional)
none no UI will be shown during the request. If this is not possible (e.g. because the user has to sign in or consent) an error is returned.
https://identityserver.github.io/Documentation/docsv2/endpoints/authorization.html
All you need to know about the identity servers are here.
https://identityserver.github.io/Documentation/
I have question regarding setup of access token renewal/refresh. Our Setup:
Implicit flow
Angular SPA using bearer token for API
Thin MVC frontend serving cshtml containing SPA
Short access token (10min)
20 min Idsrv cookie sliding (used as activity timeout)
The application has to apply to some strict security rules and intellectual property.
We need to renew the access token before it expires and API returns 401.
I’ve looked at the oidc-client-js to handle that. But that would remove the option of authenticating the static files like we do today, since there would no longer be a cookie for the MVC app.
Is there a way of securing them, or is that just something that we have to accept when building a SPA with OpenID Connect?
If you would like to enforce authorization on static files then this needs to be done by server-side code. Since your client is using an MVC backend, my recommendation would be to use the Hybrid Flow in conjunction with the Katana OpenID Connect middleware. You may then pass on any tokens you would like to use from the server-side code to your SPA via your view (cshtml).
The middleware required is available on NuGet:
install-package Microsoft.Owin.Security.Cookies
install-package Microsoft.Owin.Security.OpenIdConnect
The following snippet allows for configuration in your OWIN pipeline (taken and slightly altered from this tutorial):
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44319/identity",
ClientId = "mvc",
RedirectUri = "https://localhost:44319/",
ResponseType = "code id_token",
Scope = "openid offline_access",
SignInAsAuthenticationType = "Cookies"
});
Using this flow, you are no longer given tokens immediately but will need to exchange the auth code returned ("code" grant type) for a pair of tokens being the:
access_token (the one you are already receiving in implicit flow)
refresh_token (this can be used at the token endpoint to renew the access_token)
The main things to note about the above configuration are response type and scope.
Response type is no longer just asking for tokens (implicit) but now asks for code.
Scope includes "offline_access" scope which will return the refresh_token.
Like this we have solved both your access token expiry problem and have begun to solve your static asset problem by moving authorization to the back-end. To help you with the next part I would need to know how you are serving your assets as there are different ways depending on whether you are using OWIN to serve or IIS.
I largely followed this tutorial on how to do client authentication with Google Sign-In, get a JWT, and verify the JWT on the server on each request using Google's tokeninfo endpoint.
Everything works great except the tokens expire after 60 min and I don't know how to refresh the token.
The API server should not be involved in this refresh. The client is responsible for getting a refreshed token from the authentication service (google in this case) but there is no documentation on how to do that that I've found.
What I've observed is that the id_token is actually automatically updated by the gapi library before expires_at passes, usually about 5min before.
authInstance = gapi.auth2.getAuthInstance()
currentUser = authInstance.currentUser.get()
authResponse = currentUser.getAuthResponse()
You can then get the id_token and expired_at by doing:
authResponse.id_token
authResponse.expires_at
You can monitor for this update by doing:
authResponse.listen(function (gUser) {
const jwt = gUser.getAuthResponse().id_token
// ...you now have an updated jwt to send in all future API calls
}