I have been looking for a solution for a while now.
All authentication system is in place, I get my token but when I use it to retrieve the data I get a 404 jwt not found.
I have an emergency on this project, a help will help me a lot.
this is my security.yaml:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
json_login:
check_path: /api/login_check # or api_login_check as defined in config/routes.yaml
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/api
stateless: true
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
lazy: true
provider: app_user_provider
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
- { path: ^/api/login, roles: PUBLIC_ACCESS }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
Pour la declaration du controller:
api_login_check:
path: /api/login_check
You have to do the following;
go to /config/packages/lexik_jwt_authentication.yaml
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_extractors:
authorization_header:
enabled: true
prefix: Bearer
name: Authorization
cookie: // if you are using cookie
enabled: true
name: cookie_name // set the cookie name
If you are using httpClient; then you can Authorization: 'Bearer ' .$token in your header as follows;
$headers = [
'Authorization' => 'Bearer '.$token,
'Content-Type' => 'application/json',
];
NOTE: make sure you have jwt directory, where you have private and public keys.
Related
I'm trying to allow only to register (POST method) a new user (route: /api/users), I tried to follow the documentation (https://symfony.com/doc/current/security/firewall_restriction.html#restricting-by-http-methods), but when I test with Postman, I still manage to see all users with the GET method.
The security.yaml file :
security:
# https://symfony.com/doc/current/security/authenticator_manager.html
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#c-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
App\Entity\User:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
registration:
pattern: ^/api/users
stateless: true
methods: [POST]
login:
pattern: ^/api/login
stateless: true
json_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/api
stateless: true
jwt: ~
main:
lazy: true
provider: app_user_provider
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
# access_control:
# - { path: ^/api/login, roles: PUBLIC_ACCESS }
# - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
Short version:
firewalls:
registration:
pattern: ^/api/users
stateless: true
methods: [POST]
What I should see when trying to access /api/users with the GET method is a code 401, "JWT Token not found".
But I don't, I see the users and their datas.
I had to configure it in the access control at the end:
access_control:
- { path: ^/api/users, roles: IS_AUTHENTICATED_FULLY, methods: [GET, PUT, DELETE] }
I have two entities User and Merch.
A User uses a form and authenticates with his username and password.
A Merch uses an iPad app and authenticates with their merchCode (integer eg:11) and password.
With JWT Authentification I can generate a token for User.
The problem is I don't know what do to generate a token for Merch, too.
I want to use two different paths:
/api/login_check_user
/api/login_check_merch
for Merch I want to return a Response contain token + marchId
my security.yaml
security:
encoders:
App\Entity\User:
algorithm: argon2i
App\Entity\Merch:
algorithm: auto
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
# used to reload user from session & other features (e.g. switch_user)
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: true
json_login:
check_path: /api/login_check_user
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
refresh:
pattern: ^/api/token/refresh
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
anonymous: true
# access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/validator, roles: ROLE_VALIDATOR }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
How can I solve this?
With Lexik, we can override the response with events:
https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/2-data-customization.md#eventsjwt_created---adding-custom-data-or-headers-to-the-jwt
So you sould have only one firewall
I'd like to add the "Authorize" button on Swagger, like described here : https://api-platform.com/docs/core/jwt#documenting-the-authentication-mechanism-with-swaggeropen-api
I installed LexikJWTAuthenticationBundle, it works fine with Curl. But when I browse to http://localhost:8000/api, I only see {"code":401,"message":"JWT Token not found"}.
Am I missing something?
Here's my security.yaml:
security:
encoders:
App\Entity\User:
algorithm: bcrypt
providers:
db_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api_login:
pattern: ^/api/login
stateless: true
anonymous: true
form_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
api:
pattern: ^/api
stateless: true
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
pattern: ^/
anonymous: ~
provider: db_provider
form_login:
login_path: app_security_login
check_path: app_security_login
csrf_token_generator: security.csrf.token_manager
logout:
path: /logout
target: /
remember_me:
secret: '%kernel.secret%'
lifetime: 604800
path: /
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
access_decision_manager:
strategy: unanimous
And my api_platform.yaml:
api_platform:
title: 'My project'
version: '0.0.1'
mapping:
paths: ['%kernel.project_dir%/src/Entity']
swagger:
api_keys:
apiKey:
name: Authorization
type: header
Bit late to this, but I faced this same issue. Your security configuration is stating that any route beginning with /api requires authentication, which includes /api itself. If you want to keep the documentation on the /api route, add a trailing slash to the security configuration;
firewalls:
...
api:
pattern: ^/api/
and
access_control:
- { path: ^/api/, roles: IS_AUTHENTICATED_FULLY }
This will leave /api as publicly accessible, whilst requiring a valid token to be provided for /api/*.
Alternatively, you can leave the security configuration as it is and move the documentation to a different URL (e.g. /docs). For this, you may need to add /docs as an IS_AUTHENTICATED_ANONYMOUSLY path under access_control depending on your other rules.
Then when the documentation page is accessible, click the Authorize button at the top of the page and enter Bearer <valid JWT token>.
It's old but here is the solution in 2021
You have to decorate open api factory
Edit :
Don't put hyphen (-) in the name of the authorization and in the scheme key otherwise it won't work (probably other special characters)
In config/packages/api_platform.yaml :
swagger:
versions: [3]
api_keys:
JWT: // The name of the authorization to display on swagger UI
name: Authorization
type: header
In config/services.yaml :
App\OpenApi\JwtDecorator:
decorates: 'api_platform.openapi.factory'
arguments: [ '#App\OpenApi\JwtDecorator.inner' ]
autoconfigure: false
enter code here
The decorating service : in OpenApi\JwtDecorator
class JwtDecorator implements OpenApiFactoryInterface
{
public function __construct(
private OpenApiFactoryInterface $decorated
) {}
public function __invoke(array $context = []): \ApiPlatform\Core\OpenApi\OpenApi
{
$openApi = ($this->decorated)($context);
$schemas = $openApi->getComponents()->getSecuritySchemes();
$schemas['JWT'] = new \ArrayObject([
'type' => 'http',
'scheme' => 'bearer',
'bearerFormat' => 'JWT'
]);
return $openApi;
}
}
I could fix my problem. In my case problem was, in public and private openssl keys. First I fixed it, the second, problem was in encoding. I used the source below to achieve result. Just take a look to link below
LexikJWTAuthenticationBundleSandbox
I am using LexikJWTBundle for a RESTful API.
Login works just fine and I get my token. But when I make a GET request I get a 401 with no content.
The Authorization header seems ok since I get this in the profiler:
Request Headers: authorization: Bearer {token}
Request Server Parameters: HTTP_AUTHORIZATION: Bearer {token}
The 401 I get is from: https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Security/Firewall/JWTListener.php#L80
I've tried different solutions but still it's not working.
Would you have any idea on how to resolve/debug this?
My config:
# config.yml
...
lexik_jwt_authentication:
private_key_path: %kernel.root_dir%/var/jwt/private.pem # ssh private key path
public_key_path: %kernel.root_dir%/var/jwt/public.pem # ssh public key path
pass_phrase: 'TEST' # ssh key pass phrase
token_ttl: 86400 # token ttl - defaults to 86400
And
# security.yml
security:
role_hierarchy:
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_SONATA_ADMIN, ROLE_ALLOWED_TO_SWITCH]
# http://sonata-project.org/bundles/admin/2-3/doc/reference/security.html
# set access_strategy to unanimous, else you may have unexpected behaviors
access_decision_manager:
strategy: unanimous
encoders:
FOS\UserBundle\Model\UserInterface: sha512
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api_login:
pattern: ^/api/login # Default: .*
provider: fos_userbundle
# form login
form_login:
login_path: fos_user_security_login
# csrf_provider: form.csrf_provider # Default: my.csrf_provider.id
# LexikJWT # 09/01/15 - Note: provient de la configuration officielle.
check_path: api_login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
anonymous: true # Default: ~
api:
pattern: ^/api
stateless: true
lexik_jwt:
authorization_header: # check token in Authorization Header
enabled: true
prefix: Bearer
anonymous: true
access_control:
# Secured part of the site
# This config requires being logged for the whole site and having the admin role for the admin part.
# Change these rules to adapt them to your needs
- { path: "^/api/contacts$", roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [POST] }
- { path: "^/api/users/dt$", roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
- { path: "^/api/users$", roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [POST] }
- { path: "^/api", roles: [IS_AUTHENTICATED_FULLY, ROLE_API] }
I just found a solution on the same problem
Here my security.yml
firewalls:
dev:
pattern: ^/(_(profiler|wdt|error)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: true
provider: user_db
form_login:
check_path: /api/login_check
username_parameter: _username
password_parameter: _password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
api:
pattern: ^/api
stateless: true
lexik_jwt:
authorization_header: # check token in Authorization Header
enabled: true
prefix: Bearer
throw_exceptions: false # When an authentication failure occurs, return a 401 response immediately
create_entry_point: true # When no authentication details are provided, create a default entry point that returns a 401 response
authentication_provider: lexik_jwt_authentication.security.authentication.provider
My problem was the username and the password parameters. I change "username" by "_username" and "password" by "_password"
You should add the ROLE_API in the role_hierarchy of your security.yml :
role_hierarchy:
# ...
ROLE_API: [ROLE_USER]
Then, users ranked with ROLE_API can access routes restricted to IS_AUTHENTICATED_FULLY.
Also, if you are using a web server, try to use your application using the built-in server (i.e. app/console server:run).
Apache seems to modify the token in headers.
LexikJWTBundle generates token so user's credentials are valid.
Problem occurs when you try to access secured routes (behind "^/api" path).
You should definitely check roles assigned to user. Maybe ROLE_API is missing and user is not fully authenticated.
While Using FOSOAuthServerBundle as OAuthServer and HWIOAuthBundle as OAuth Client, these both application have FOSUSerBundle integration.
I am facing issue in retrieving access token, which will use in sending user response to client application.
Please anyone can help me out.
<?php
public function userAction(Request $request)
{
$user = $this->get('security.context')->getToken()->getUser();
if($user) {
$user = $this->getDoctrine()->getRepository('EparUserBundle:User')->find(
$this->get('security.context')->getToken()->getUser()
);
return new JsonResponse(array(
'id' => $user->getId(),
'username' => $user->getUsername(),
'email' => $user->getEmail()
));
}
return new JsonResponse(array(
'message' => 'User is not identified'
));
}
FosOAuthServer config.yml and security.yml below:
fos_oauth_server:
db_driver: orm # Driver availables: orm, mongodb, or propel
client_class: Epar\Bundle\UserBundle\Entity\Client
access_token_class: Epar\Bundle\UserBundle\Entity\AccessToken
refresh_token_class: Epar\Bundle\UserBundle\Entity\RefreshToken
auth_code_class: Epar\Bundle\UserBundle\Entity\AuthCode
service:
storage: fos_oauth_server.storage.default
user_provider: fos_user.user_manager
client_manager: fos_oauth_server.client_manager.default
access_token_manager: fos_oauth_server.access_token_manager.default
refresh_token_manager: fos_oauth_server.refresh_token_manager.default
auth_code_manager: fos_oauth_server.auth_code_manager.default
options:
# Prototype
#key: []
# Example
# supported_scopes: string
# Changing tokens and authcode lifetime
access_token_lifetime: 3600
refresh_token_lifetime: 1209600
auth_code_lifetime: 30
supported_scopes: user
# Token type to respond with. Currently only "Bearer" supported.
#token_type: string
#realm:
# Enforce redirect_uri on input for both authorize and token steps.
#enforce_redirect: true or false
# Enforce state to be passed in authorization (see RFC 6749, section 10.12)
#enforce_state: true or false
template:
engine: twig
Security.yml
# app/config/security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
administration:
switch_user: true
context: user
pattern: /administration*
form_login:
provider: fos_userbundle
login_path: /administration/login
check_path: /administration/login_check
failure_path: /administration/login
default_target_path: /administration/
use_forward: false
use_referer: true
always_use_default_target_path: true
logout:
path: /administration/logout
target: /administration/login
anonymous: ~
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout: true
anonymous: true
oauth_token:
pattern: ^/oauth/v2/token
security: false
oauth_authorize:
pattern: ^/oauth/v2/auth
form_login:
provider: fos_userbundle
check_path: /oauth/v2/auth_login_check
login_path: /oauth/v2/auth_login
use_referer: true
anonymous: true
context: connect
# Add your favorite authentication process here
api:
pattern: ^/api
fos_oauth: true
stateless: true
anonymous: true # can be omitted as its default value
access_control:
- { path: ^/administration/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/administration/login_check, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: [ IS_AUTHENTICATED_ANONYMOUSLY ] }
- { path: "/administration.*", role: ROLE_ADMIN }
HWIOAuthBundle application config.yml & security.yml
config.yml
hwi_oauth:
http_client:
timeout: 10 # Time in seconds, after library will shutdown request, by default: 5
verify_peer: false # Setting allowing you to turn off SSL verification, by default: true
ignore_errors: false # Setting allowing you to easier debug request errors, by default: true
max_redirects: 1 # Number of HTTP redirection request after which library will shutdown request,
# by default: 5
#this is my custom user provider, created from FOSUBUserProvider - will manage the
#automatic user registration on your site, with data from the provider (facebook. google, etc.)
#and also, the connecting part (get the token and the user_id)
connect:
# confirmation: true
account_connector: my_user_provider
# name of the firewall in which this bundle is active, this setting MUST be set
firewall_name: main
fosub:
username_iterations: 30
properties:
# these properties will be used/redefined later in the custom FOSUBUserProvider service.
github: githubID
atssso: atsssoID
resource_owners:
github:
type: github
client_id: *******
client_secret: ********
scope: "user:email"
atssso:
type: oauth2
client_id : 4_1u2nw1clcdy8o4kk84o004s0000oo0kkkw8ow8sg8koowo0c4c
client_secret: v5sa4t4sylcgsgkg8cosws4400k4s0okg48cgc8ccgk8sg4o4
access_token_url: http://192.168.11.71/atssso/web/app_dev.php/oauth/v2/token
authorization_url: http://192.168.11.71/atssso/web/app_dev.php/oauth/v2/auth
infos_url: http://192.168.11.71/atssso/web/app_dev.php/api/user
user_response_class: HWI\Bundle\OAuthBundle\OAuth\Response\PathUserResponse
scope: "user"
paths:
identifier: id
nickname: username
#realname: ["first_name", "last_name"]
realname: username
email: email
# here you will add one (or more) configurations for resource owners
security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_USER
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /login
check_path: /login_check
oauth:
resource_owners:
github: "/login/check-github"
atssso: "/login/service/atssso"
login_path: /login
failure_path: /login
oauth_user_provider:
#this is my custom user provider, created from FOSUBUserProvider - will manage the
#automatic user registration on your site, with data from the provider (facebook. google, etc.)
service: my_user_provider
logout: true
anonymous: true
login:
pattern: ^/login$
security: false
remember_me:
key: "%secret%"
lifetime: 31536000 # 365 days in seconds
path: /
domain: ~ # Defaults to the current domain from $_SERVER
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }