How to access JWT claims from API handler functions in go-swagger? - jwt

I'm using go-swagger with BearerAuth using JWT tokens. Along with the actual token I'm receiving claims which include such data as username.
How can I access claims in api.ItemsCreateItemHandler function below?
package restapi
func configureAPI(api *operations.MyAPI) http.Handler {
api.BearerAuth = func(token string) (interface{}, error) {
jwtToken := strings.Replace(token, "Bearer ", "", -1)
// skipped token verification
claims, _ := parsedToken.Claims.(jwt.MapClaims)
}
api.ItemsCreateItemHandler = items.CreateItemHandlerFunc(func(params items.CreateItemParams, principal interface{}) middleware.Responder {
// FIXME: Here I need to be able to access JWT claims
if err := createItem(params.Body, claims); err != nil {
return nil // handle error
}
return items.NewCreateItemCreated()
})
}

First your BearerAuth implementation is meant to return the security principal (which can be your claims in this case), this value will subsequently be passed to your handler in the principal argument.
So the way to do this is:
package restapi
import (
jwt "github.com/dgrijalva/jwt-go"
// ...
)
func configureAPI(api *operations.MyAPI) http.Handler {
api.BearerAuth = func(token string) (interface{}, error) {
jwtToken := strings.Replace(token, "Bearer ", "", -1)
// skipped token verification
claims, _ := parsedToken.Claims.(jwt.MapClaims)
return claims, nil
}
api.ItemsCreateItemHandler = items.CreateItemHandlerFunc(func(params items.CreateItemParams, principal interface{}) middleware.Responder {
claims, ok := principal.(jwt.MapClaims)
if !ok {
// handle error
}
if err := createItem(params.Body, claims); err != nil {
return nil // handle error
}
return items.NewCreateItemCreated()
})
}
You can make this less cumbersome by using the --principal jwt.MapClaims option to swagger generate so that it uses this type for the claims instead of interface{}.

A JWT is made up of 3 parts, split by punctuation - the token itself is base64 encoded.
For example, heres a token from https://jwt.io/
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
You'll want to split and decode, you're after the second part which contains the payload which is just plain JSON.
So in psuedo code it'll look something like;
json = Base64Decode(split(".", yourData)[1])
You'll see more concrete example at https://jwt.io/

I have a class that store token and contains parse method:
import io.jsonwebtoken.*;
#AllArgsConstructor
public class RawAccessJwtToken implements JwtToken {
private String token;
#Override
public String getToken() {
return token;
}
public Jws<Claims> parseClaims(String signingKey) {
try {
return Jwts.parser().setSigningKey(signingKey).parseClaimsJws(this.token);
} catch (UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) {
throw new BadCredentialsException("Invalid JWT token: " + e);
} catch (ExpiredJwtException expiredException){
throw new JwtExpiredTokenException(this, "JWT Token expired", expiredException);
}
}
}
With that class I can extract my users role:
Jws<Claims> claimsJws = token.parseClaims(signingKey);
List<String> scopes = claimsJws.getBody().get("scopes",
List.class);

Related

How can I inherit bearer token from collection? (POSTMAN, Golang RESTAPI)

I am able to verify the JWT Token, by manually setting each individual request with the bearer token, but whenever I set them to inherit auth from parent, it returns Unauthorized, it says clearly that it's taking the auth from the name of the collection, and I've set the collection to the bearer token.
Here is the JWTMiddleware:
func JWTMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := strings.Split(r.Header.Get("Authorization"), "Bearer ")
if len(authHeader) != 2 {
fmt.Println("Malformed token")
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Malformed Token"))
} else {
jwtToken := authHeader[1]
token, err := jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return []byte(os.Getenv("JWT_SECRET")), nil
})
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
ctx := context.WithValue(r.Context(), "props", claims)
next.ServeHTTP(w, r.WithContext(ctx))
} else {
fmt.Println(err)
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Unauthorized"))
}
}
})
}
Here is how the token is generated:
func generateJWT() (JWTToken, error) {
signingKey := []byte(os.Getenv("JWT_SECRET"))
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"exp": time.Now().Add(time.Hour * 1 * 1).Unix(),
})
tokenString, err := token.SignedString(signingKey)
return JWTToken{tokenString}, err
}
Here is how my routes are structured:
var Routes = router.RoutePrefix{
"/generate",
[]router.Route{
router.Route{
"gen_token",
"GET",
"",
gen_token,
false,
},
router.Route{
"testToken",
"GET",
"/test",
testToken,
true,
},
},
}
I am considering setting a global variable that I can set as the token for testing purposes, what would the solution be?

Possible to return 401 instead of 403 for expired token?

I want to be able to return a 401 on JWT token expiry (which I believe is the correct response?) but it returns a 403 no matter what
here is where I tell swagger tools to use my bearer token verification logic:
swaggerTools.initializeMiddleware(swaggerObject, (middleware) => {
// Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
app.use(middleware.swaggerMetadata());
//enable cors
app.use(
cors({
methods: ["GET", "POST", "PATCH", "DELETE"],
origin: "*",
preflightContinue: false,
optionsSuccessStatus: 204,
})
);
//verify bearer token for protected apis
app.use(
middleware.swaggerSecurity({
Bearer: (req, authOrSecDef, token, callback) =>
//if this is a protected endpoint then token is verified to allow or deny access
securityService.verifyToken(
req,
authOrSecDef,
token,
callback
),
})
);
and here is my verifyToken function..
verifyToken: (req, authOrSecDef, token, callback) => {
const sendError = (error) => {
if (error) {
if (error.name === "TokenExpiredError") {
return new Problem(401, error.message);
}
} else {
return new Problem(403);
}
};
if (token && token.toLowerCase().indexOf("bearer ") === 0) {
var tokenString = token.split(" ")[1];
let completeDecodedToken = jwt.decode(tokenString, { complete: true });
if (!completeDecodedToken) {
return callback(sendError());
}
//use header.kid to find correct cognito jwk to use
let jwk = jwks.keys.find(
(jwk) => jwk.kid == completeDecodedToken.header.kid
);
if (!jwk) {
//must have passed in a token obtained from somewhere else
return callback(sendError());
}
const pem = jwkToPem(jwk);
jwt.verify(
tokenString,
pem,
{ algorithms: ["RS256"] },
(verificationError, decodedToken) => {
if (verificationError === null) {
// check if the issuer matches
var issuerMatch =
decodedToken.iss ===
`https://cognito-idp.${process.env.AWS_REGION}.amazonaws.com/${process.env.COGNITO_USER_POOL_ID}`;
if (issuerMatch) {
//add the token to the request so that we
//can access it downstream in endpoint if we need
req.auth = decodedToken;
req.tokenString = tokenString;
//if there is no error, just return null in the callback
return callback(null);
} else {
console.error("Issuer did not match");
//return the error in the callback if there is one
return callback(sendError());
}
} else {
//return the error in the callback if the JWT was not verified
return callback(sendError(verificationError));
}
}
);
} else {
return callback(sendError());
}
},
but actually when I look in the swagger-tools source (swagger-security.js) I only see 403 in there.. any advice ?
You see 403 always because that is the else part and your error object is null, If you are able to debug then you can console log the error
Also your assumption is that error is returned from below line, which is highly likely wrong because error is null.
//return the error in the callback if the JWT was not verified
return callback(sendError(verificationError));
In my opinion, error is returned from
else {
return callback(sendError());
}
If that is the case then you can send your custom "UnauthorizedError" object from the desired place.

Refreshing access token with multiple requests

Im struggling with getting axios interceptors to work.
When my token expires, i need it to refresh the access token and retry the original request once the token is refreshed.
I have this part working.
The problem is if i have concurrent api calls it will only retry the first request when the token was first invalid.
Here is my interceptor code:
export default function execute() {
let isRefreshing = false
// Request
axios.interceptors.request.use(
config => {
var token = Storage.getAccessToken() //localStorage.getItem("token");
if (token) {
console.log('Bearer ' + token)
config.headers['Authorization'] = 'Bearer ' + token
}
return config
},
error => {
return Promise.reject(error)
}
)
// Response
axios.interceptors.response.use(
response => {
return response
},
error => {
const originalRequest = error.config
// token expired
if (error.response.status === 401) {
console.log('401 Error need to reresh')
originalRequest._retry = true
let tokenModel = {
accessToken: Storage.getAccessToken(),
client: 'Web',
refreshToken: Storage.getRefreshToken()
}
//Storage.destroyTokens();
var refreshPath = Actions.REFRESH
if (!isRefreshing) {
isRefreshing = true
return store
.dispatch(refreshPath, { tokenModel })
.then(response => {
isRefreshing = false
console.log(response)
return axios(originalRequest)
})
.catch(error => {
isRefreshing = false
console.log(error)
// Logout
})
} else {
console.log('XXXXX')
console.log('SOME PROBLEM HERE') // <------------------
console.log('XXXXX')
}
} else {
store.commit(Mutations.SET_ERROR, error.response.data.error)
}
return Promise.reject(error)
}
)
}
I'm not sure what i need in the else block highlighted above.
EDIT:
When I do
return axios(originalRequest)
in the else block it works, however im not happy with the behaviours. It basically retries all the requests again and again until the token is refreshed.
I would rather it just retried once after the token had been refreshed
Any ideas
Thanks
You can just have additional interceptor which can refresh token and execute your pending requests.
In this, countDownLatch class can help.
Here is sample Interceptor code,
class AutoRefreshTokenRequestInterceptorSample() : Interceptor {
companion object {
var countDownLatch = CountDownLatch(0)
var previousAuthToken = ""
const val SKIP_AUTH_TOKEN = "SkipAccessTokenHeader"
const val AUTHORIZATION_HEADER = "AUTHORIZATION_HEADER_KEY"
}
#Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response? {
val request = chain.request()
if (shouldExecuteRequest(request)) {
// Execute Request
val response = chain.proceed(request)
if (!response.isSuccessful) {
// Failed Case
val errorBody = response.peekBody(java.lang.Long.MAX_VALUE).string()
val error = parseErrorModel(errorBody)
// Gives Signal to HOLD the Request Queue
countDownLatch = CountDownLatch(1)
handleError(error!!)
// After updating token values, execute same request with updated values.
val updatedRequest = getUpdatedRequest(request)
// Gives Signal to RELEASE Request Queue
countDownLatch.countDown()
//Execute updated request
return chain.proceed(updatedRequest)
} else {
// success case
return response
}
}
// Change updated token values in pending request objects and execute them!
// If Auth header exists, and skip header not found then hold the request
if (shouldHoldRequest(request)) {
try {
// Make this request to WAIT till countdown latch has been set to zero.
countDownLatch.await()
} catch (e: Exception) {
e.printStackTrace()
}
// Once token is Updated, then update values in request model.
if (previousAuthToken.isNotEmpty() && previousAuthToken != "newAccessToken") {
val updatedRequest = getUpdatedRequest(request)
return chain.proceed(updatedRequest)
}
}
return chain.proceed(request)
}
private fun handleError(error: ErrorDto) {
// update your token as per your error code logic
//Here it will make new API call to update tokens and store it in your local preference.
}
/***
* returns Request object with updated token values.
*/
private fun getUpdatedRequest(request: Request): Request {
var updateAuthReqBuilder: Request.Builder = request.newBuilder()
var url = request.url().toString()
if (url.contains(previousAuthToken.trim()) && previousAuthToken.trim().isNotEmpty()) {
url = url.replace(previousAuthToken, "newAccessToken")
}
updateAuthReqBuilder = updateAuthReqBuilder.url(url)
// change headers if needed
return updateAuthReqBuilder.build()
}
private fun shouldExecuteRequest(request: Request) =
shouldHoldRequest(request) && isSharedHoldSignalDisabled()
/**
* If count down latch has any value then it is reported by previous request's error signal to hold the whole pending chain.
*/
private fun isSharedHoldSignalDisabled() = countDownLatch.count == 0L
private fun shouldHoldRequest(request: Request) = !hasSkipFlag(request) && hasAuthorizationValues(request)
private fun hasAuthorizationValues(request: Request) = isHeaderExist(request, AUTHORIZATION_HEADER)
private fun hasSkipFlag(request: Request) = isHeaderExist(request, SKIP_AUTH_TOKEN)
private fun isHeaderExist(request: Request, headerName: String): Boolean {
return request.header(headerName) != null
}
private fun parseErrorModel(errorBody: String): Error? {
val parser = JsonParser()
// Change this logic according to your requirement.
val jsonObject = parser.parse(errorBody).asJsonObject
if (jsonObject.has("Error") && jsonObject.get("Error") != null) {
val errorJsonObj = jsonObject.get("Error").asJsonObject
return decodeErrorModel(errorJsonObj)
}
return null
}
private fun decodeErrorModel(jsonObject: JsonObject): Error {
val error = Error()
// decode your error object here
return error
}
}
This is how I do:
let isRefreshing = false;
let failedQueue = [];
const processQueue = (error, token = null) => {
failedQueue.forEach(prom => {
if (error) {
prom.reject(error);
} else {
prom.resolve(token);
}
});
failedQueue = [];
};
axios.interceptors.response.use(
response => response,
error => {
const originalRequest = error.config;
if (error.response.status === 400) {
// If response is 400, logout
store.dispatch(logout());
}
// If 401 and I'm not processing a queue
if (error.response.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
// If I'm refreshing the token I send request to a queue
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject });
})
.then(() => {
originalRequest.headers.Authorization = getAuth();
return axios(originalRequest);
})
.catch(err => err);
}
// If header of the request has changed, it means I've refreshed the token
if (originalRequest.headers.Authorization !== getAuth()) {
originalRequest.headers.Authorization = getAuth();
return Promise.resolve(axios(originalRequest));
}
originalRequest._retry = true; // mark request a retry
isRefreshing = true; // set the refreshing var to true
// If none of the above, refresh the token and process the queue
return new Promise((resolve, reject) => {
// console.log('REFRESH');
refreshAccessToken() // The method that refreshes my token
.then(({ data }) => {
updateToken(data); // The method that sets my token to localstorage/Redux/whatever
processQueue(null, data.token); // Resolve queued
resolve(axios(originalRequest)); // Resolve current
})
.catch(err => {
processQueue(err, null);
reject(err);
})
.then(() => {
isRefreshing = false;
});
});
}
return Promise.reject(error);
},
);
I don't know what is the schema of your token (after decrypted) but one of the attributes which is a good practice to keep is the exp "expiration_date".
Said so, having the expiration date you can know when you should refresh your token.
Without understanding your architecture is hard to inform the right solution. But let's say you are doing everything manually, usually onIdle/onActive is when we check if the user session is still ok, so at this time you could use the token info to know if you should refresh its value.
It is important to understand this process because the token should be refreshed only if the user is constantly active and it is about to expire (like 2min before).
Please refer to angular version of the code for which i was facing the same problem and after changing many approaches this was my final code which is working at its best.
Re Initaite the last failed request after refresh token is provided

I need help to verify that jwt is valid or otherwise create a new one and if the token sent is not correct return an error in nestjs middleware

I have already implemented the jwt and it works correctly but when creating a middleware that verifies that the token is still active and that it is valid, if the token has already expired, you must create a new one in case you can not create a new one, return a 404 error with a message, So far I have only been able to obtain the token and decode it, I need to be able to verify it and return an error response or let it continue.
this is my middleware code code:
import { JwtService } from '#nestjs/jwt';
import { Injectable, NestMiddleware } from '#nestjs/common';
#Injectable()
export class JwtMiddleware implements NestMiddleware {
valid = null;
decode = null;
cleanToken = null;
constructor(private readonly jwtServ: JwtService) {}
use(req: Request, res: Response, next: Function) {
const token = req.headers['authorization'];
try {
this.cleanToken = token.replace('Bearer','').trim();
this.decode = this.jwtServ.decode(this.cleanToken);
} catch (error) {
// console.log(error);
}
try {
this.valid = this.jwtServ.verify(this.cleanToken);
} catch (error) {
console.log(error.name);
console.log(error.message);
console.log(error.expiredAt);
}
next();
}
}
up to here I could only print in console the error of verifying jwt but it is not the correct way to do it besides that I can not return a valid answer to the client
console print:
TokenExpiredError
jwt expired
2019-03-27T00:18:56.000Z
I searched the jwt documentation to see how to validate the token and found it:
https://github.com/auth0/node-jsonwebtoken
// verify a token symmetric
jwt.verify(token, 'shhhhh', function(err, decoded) {
console.log(decoded.foo) // bar
});
but in nestjs it does not work that way. The function "function (err, decoded)" can not be implemented like this, so it marks me errors so I had to put it in a trycatch
I also tried this:
this.jwtServ.verify(token,(err, decoded) => {
if (err) {
return res.status(401).json({
ok: false,
message: 'Invalid Token',
errors: err
});
}
req.user = decoded.user;
next();
});
in the nestjs documentation he says:
The Nest middleware, by default, are equal to express middleware. Here's a great list of the middleware capabilities copied from the official express documentation
https://docs.nestjs.com/middleware
I've already tried this and it does not work
return res.status(401).json({
ok: false,
message: 'Invalid Token',
errors: err
});
Any help is welcome, thanks!
My solution this:
try {
const validated = jwt.verify(token, {publicKey: myPublicKey})
return validated
} catch(error) {
// here comes if token invalid or expired
}
try this.. use 'jsonwebtoken' package
import * as jwt from 'jsonwebtoken';
jwt.verify(token, 'shhhhh', function(err, decoded){
console.log(decoded.foo) // bar
});
At present, through your description, I think your main problem is that you want to implement jwt authentication and interrupt the request in the middleware and return the expected return value, you can refer to my example.
// jwt.middleware.ts
import { Injectable, NestMiddleware } from '#nestjs/common'
import { Request, Response, NextFunction } from 'express'
import jwt from 'jsonwebtoken'
#Injectable()
export class JwtMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
if (!req.headers.authorization) {
res.writeHead(401, { 'content-type': 'application/json' })
res.write(JSON.stringify({
msg: 'Authorization is required',
}))
res.end()
} else {
const token = req.headers.authorization.replace('Bearer','').trim()
const validated = jwt.verify(token, 'secret_key')
// Other requests using this middleware can get the parsed value in the
// parameter, you can also analyze the parsed value and return res as
// above for those that do not match
req.body._validated = validated
}
next()
}
}
As above, you can indicate the completion of middleware execution by executing the next function, and the processed content will be passed to the next layer, or you can call res.end to interrupt the request and describe the content of res.
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(JwtMiddleware).exclude('api/users/login').forRoutes('api')
}
}
Refer to:
https://docs.nestjs.com/middleware
How to send response from middleware created in a Nest fastify server?
https://www.npmjs.com/package/jsonwebtoken

How can I do this redirection from ballerinalang?

I've implemented a REST endpoint in ballerinalang called https://localhost:9090/isValidUser. And here is my code below
import ballerina.net.http;
#http:configuration {
basePath:"/",
httpsPort:9090,
keyStoreFile:"${ballerina.home}/bre/security/wso2carbon.jks",
keyStorePassword:"wso2carbon",
certPassword:"wso2carbon",
trustStoreFile:"${ballerina.home}/bre/security/client-truststore.jks",
trustStorePassword:"wso2carbon"
}
service<http> authentication {
#http:resourceConfig {
methods:["POST"],
path:"/isValidUser"
}
resource isValidUser (http:Request req, http:Response res) {
println(req.getHeaders());
res.send();
}
}
Now I need to do is when I invoke that URL from the browser, I need to redirect the user to another URL called https://localhost:3000 after some validations happen within my service.
So how can I do this redirection from ballerinalang?
Ballerina has provided smooth API to do the redirection. Please check following code which elaborates the Listener endpoint redirection.
service<http:Service> redirect1 bind {port:9090} {
#http:ResourceConfig {
methods:["GET"],
path:"/"
}
redirect1 (endpoint client, http:Request req) {
http:Response res = new;
_ = client -> redirect(res, http:REDIRECT_TEMPORARY_REDIRECT_307,
["http://localhost:9093/redirect2"]);
}
}
The complete example is available in
Ballerina Redirects
In Ballerina, you need to handle the redirects yourself by setting the necessary headers and status code. The following example is a simple demo of how you can redirect in Ballerina. (note: I tried this in Ballerina 0.95.2)
import ballerina.net.http;
#http:configuration {basePath:"/hello"}
service<http> helloWorld {
#http:resourceConfig {
methods:["GET"],
path:"/"
}
resource sayHello (http:Request request, http:Response response) {
map qParams = request.getQueryParams();
var name, _ = (string)qParams.name;
if (isExistingUser(name)) {
response.setStringPayload("Hello Ballerina!");
} else {
response.setHeader("Location", "http://localhost:9090/hello/newUser");
response.setStatusCode(302);
}
_ = response.send();
}
#http:resourceConfig {path:"/newUser"}
resource newUser (http:Request request, http:Response response) {
string msg = "New to Ballerina? Welcome!";
response.setStringPayload(msg);
_ = response.send();
}
}
function isExistingUser (string name) (boolean) {
return name == "Ballerina";
}