keycloak javascript adapter request offline token - javascript

I have js application for which I use keycloak 1.7-final JavaScript adapter with public client and standard flow and it works fine but now I wanted to add offline capability to the application and don't know how to get offline token. according to the documentation the client can request offline token by adding parameter "scope=offline_access" when sending authorization request to Keycloak.
The thing is I don't know where to add the parameter. I tried to add to "keycloak.config" and "keycloak.init" but its not working.
in keycloak.config:
keycloak: {
url: 'link omitted',
realm: 'sisdn-realm',
clientId: 'sisdn',
redirect_uri: 'link omitted',
flow: 'standard',
'enable-cors': true,
scope: 'offline_access'
}
and in keycloak.init
const keycloakConf = require('keycloak')//this is the same config above
var keycloak = new keycloakConf(config.keycloak)
keycloak.init({
onLoad: 'login-required',
checkLoginIframe: false,
scope: 'offline_access'
})
.success(authenticated => {
if(!authenticated)
dispatch(loginFailure())
else {
global.keycloak = keycloak
dispatch(loginSuccess())
}
})

From the JS adapter code:
The init method doesn't accept the scope option, but the login method does.

Related

Are there security rist if my okta credentials are exposed in frontend?

I am trying to implement Okta in my app. All tutorials I saw online (even on the docs) has the config in the front-end. Sample config below:
const oktaConfig = {
issuer: process.env.NEXT_PUBLIC_OKTA_ISSUER,
clientId: process.env.NEXT_PUBLIC_OKTA_CLIENT_ID,
redirectUri: 'http://localhost:3000/login',
responseMode: 'query',
response_type: 'code',
tokenManager: {
storage: 'sessionStorage',
},
};
This can be viewed by the user in their browser. I was wondering if this has any security issues? This is how I sign-in the users (we don't use okta's sign-in page):
const oktaClient = new OktaAuth(oktaConfig);
const oktaData = await oktaClient.signInWithCredentials({ username, password });
Any thoughts if it is bad if those issuerId and cliendId are exposed or is that normal?
The issuer and client ID are public information. I like to think of a client ID like a vehicle's license plate. It's just an identifier and doesn't contain any private information. Client secrets are the only thing you need to worry about. They should never be in any frontend code.

#nestjs/swagger does not set authorization headers

Can't authorize in a route using #nestjs/swagger#5.0.9 because I dont know how to configure the Document` in a right way and I couldn't find a workable answer in authorization official docs / stackoverflow / github.
I've stumbled upon a problem with JWT authorization in swagger. I'm using "#nestjs/swagger": "^5.0.9" and after I'm getting my access-token from a public route, I'm inserting it into the swagger ui field 'Authorize' which is configured with .addBearerAuth() method, which in this version(5.0.9) has this signature
addBearerAuth(options?: SecuritySchemeObject, name?: string)
as opposed to it lower version.
I've tested my API in Postman and I'm easily get an authorization throw it, I've also created an intersector which is printing headers before route call, but unfortunately it only prints them while I'm calling a public route :/
I only know that Postman is setting a Bearer token and it goes throw the route, and nothing similar is happening with swagger.
I've tried a lot of combinations of this configuration, but I haven't come to a solution in result of which I'm getting authorized in my route method, from swagger I can't reach it because of the swagger auth is not setting an authorization header in case of a bad config or of me doing something completely wrong. And I can't figure it out.
Config of a addBearerAuth is placed lower:
// swagger config
...
const config = new DocumentBuilder()
.setTitle('SWAGGER API')
.setVersion('1.0.0')
.addBearerAuth(
{
// I was also testing it without prefix 'Bearer ' before the JWT
description: `[just text field] Please enter token in following format: Bearer <JWT>`,
name: 'Authorization',
bearerFormat: 'Bearer', // I`ve tested not to use this field, but the result was the same
scheme: 'Bearer',
type: 'http', // I`ve attempted type: 'apiKey' too
in: 'Header'
},
'access-token',
)
.build();
...
Sample of a route in my controller. Is matched with a #ApiBearerAuth() decorator which is talking to a swagger that that method is cant be reached without an authorization.
#Get('/some-route')
#ApiBearerAuth()
#UseGuards(JwtAuthenticationGuard)
getData(
#ReqUser() user: User,
): void {
this.logger.warn({user});
}
If I understood your question you need to specify in your controller which bearer token you are using. In your case:
// swagger config
...
const config = new DocumentBuilder()
.setTitle('SWAGGER API')
.setVersion('1.0.0')
.addBearerAuth(
{
// I was also testing it without prefix 'Bearer ' before the JWT
description: `[just text field] Please enter token in following format: Bearer <JWT>`,
name: 'Authorization',
bearerFormat: 'Bearer', // I`ve tested not to use this field, but the result was the same
scheme: 'Bearer',
type: 'http', // I`ve attempted type: 'apiKey' too
in: 'Header'
},
'access-token', // This name here is important for matching up with #ApiBearerAuth() in your controller!
)
.build();
...
and in your controller:
#Get('/some-route')
#ApiBearerAuth('access-token') //edit here
#UseGuards(JwtAuthenticationGuard)
getData(
#ReqUser() user: User,
): void {
this.logger.warn({user});
}

Laravel 5.5 Passport client_secret and Vue JS Auth

Good Day everyone,
I'm learning Laravel Passport and Vue.JS(standalone) at the same time.
I'm using Password Grant Token to authenticate the user.
I encounter this issue that the secret_key must be always hidden.
I have this Login Component in my vuejs where I need to add the client_secret as parameter to get access token. However, since VUEJS is a javascript framework. there's a way that someone can see the client_secret on the minified build file.
my question is that, is it just normal? is there a way to conceal the client_secret?
at first I don't mind the issue since I have implemented CORS on laravel where I can only select the allowedOrigins. My thinking is that it doesn't matter if they know the secret key as long as I can filter the allowedOrigins.
Here's my code in VUEJS
login(){
this.$validator.validateAll().then((result) => {
if (result) {
var data = {
client_id: 3,
client_secret: 'client-secret key',
grant_type: 'password',
username: this.inputs.email,
password: this.inputs.password
}
this.$http.post("oauth/token", data).then(response => {
this.$auth.setToken(response.body.access_token, response.body.expires_in + Date.now());
bus.$emit('reload');
this.$router.push('/');
})
}
});
}
Any advice will be appreciated.
Thanks in advance.
Laravel Passport has a built in way of allowing you to consume your own API with a Javascript application. It provides a simple middleware which you can add to your web middleware group (which you'll find in App\Http\Kernel):
'web' => [
// Other middleware...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
Laravel will check to see if you have a logged in user (via the standard cookie/session guard) and if so it will generate JWT for you and store it in a cookie. It will also check for this cookie's presence and validate it when you make requests to your API so you no longer need to pass an access token.
One thing to note however, is that you will need to ensure that you continue to pass your CSRF tokens with your requests (assuming you have CSRF protection turned on). If you're using Axios with Vue, you can make sure this happens very easily with the following:
window.axios.defaults.headers.common = {
'X-Requested-With': 'XMLHttpRequest',
};
With this approach you don't need to worry about access tokens at all or expose a client_id and secret to the client.
I faced the same problem and found an interesting solution.
You can add a custom endpoint on the backend and make the request from there.
All you have to do is to:
First, create a route in the api.php file Route::post('/login', 'AuthController#login');
Then, create the AuthController and login function associated with that route php artisan make:controller AuthController
Finally, install Guzzle, the HTTP client that will allow you to make a request from PHP composer require guzzlehttp/guzzle and make the request from the login function
public function login(Request $request)
{
$http = new \GuzzleHttp\Client;
try {
$response = $http->post('http://example.test/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 2,
'client_secret' => 'your_client_secret',
'username' => $request->username,
'password' => $request->password,
]
]);
return $response->getBody();
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
if($e->getCode() == 400)
{
return response()->json('Invalid Request, Please enter email or password.', $e->getCode());
}
else if($e->getCode() == 401)
{
return response()->json('Your credentials are incorrect. Please try again', $e->getCode());
}
return response()->json('Something went wrong on the server.', $e->getCode());
}
}
Now, the vue.js front end app juste needs to send a post request to http://example.test/login with the username and password to get back the access_token without knowing the client_secret since it is abstracted to the backend.
Here is the video that explains it and implements it really well.
And a presentation about some theory and how you can store and send the token from the vue.js app once you retrieve the token.
Hope this helps.

Skype Web SDK - Maintain a user session

I am using Skype Web SDK to get a user's contact list in the following manner.
Skype.initialize({
apiKey: 'a42fcebd-5b43-4b89-a065-74450fb91255',
}, function (api) {
var Application = api.application;
var client = new Application();
client.signInManager.signIn({
username: sip,
password: pwd
})
This works fine when I provide the username(sip) and password. However, when I reload the page, I have to provide the credentials again because the app re-initializes. Is there a way to maintain the user's sessions for a while after the initial login so that the page refreshes wouldn't need ask for credentials again?
I have looked through the samples and docuementation that Microsoft has and couldn't find a way. I've also tried to store the client object in the localStorage after the initialization and sign in, but when I tried to reuse the object from localStorage to get the contact list, it did not work.
http://officedev.github.io/skype-docs/Skype/WebSDK/model/api/interfaces/jcafe.signinmanager.html#signin last example explains that you can store oauth token and use it as unexpired token.
To connect to an existing app's event channel, specify id of that app:
sm.signIn({
username: "user1#company.com",
password: "password1",
id: "273867-234235-45346345634-345"
});
To sign in to Skype for Business Online using OAuth while handling the
logic of retrieving OAuth tokens yourself:
sm.signIn({
client_id: '123-456',
origins: [ 'https://webdir.online.lync.com/AutoDiscover/AutoDiscoverservice.svc/root' ],
cors: true,
get_oauth_token: function(resource) {
// Return a valid unexpired token for the specified resource if you already have one.
// Else, return a promise and resolve it once you have obtained a token.
return 'Bearer eyJ0e...';
}
});

Angular and digest auth

I use passport.js with my node.js server.
I have an RESTFull api and want to implement digest auth so that my user can then interact with my API.
In Angular, using $resource, how can I implement the digest auth process? I see that using username, realm and password I must compute a "nonce" using MD5...
If you already did that, I would be happy to learn.
your can put the token in the http header if user login success.
In angularjs you can do this:
//put the user token to the default http request headers after user login.
$httpProvider.defaults.headers.get['API-Token'] = 'vy4eUCqpQmGoeWsnHKwCQw';
//create service and push the token to the request headers.
angular.module('usersService', ['ngResource'])
.factory('User', function($resource, api-token) {
var User = $resource('http://api.test.com\\:8080/1.0/users', { }, {
query: {
method: 'GET',
isArray: true,
headers: { 'API-Token': api-token }
}
});
return User
});

Categories