lexik / LexikJWTAuthenticationBundle

JWT authentication for your Symfony API
MIT License
2.5k stars 610 forks source link

After token removal, an empty login form will get a new token #367

Closed silverbackdan closed 6 years ago

silverbackdan commented 6 years ago

I'm struggling to work out the culprit, but I am also using gesdinet/jwt-refresh-token-bundle

I have a problem where I login (using FOSUserBundle as a provider as well although it doesn't matter if I use the entity users or the in memory users). I then logout and remove the token.

If I enter new (valid or invalid) information into my login field again, then the authentication process is as expected. However, if after logout out, I revisit the login form and input no username or password, I'm logged back in as the same user as before. The token is returned (with a refresh token as I'm using the bundle mentioned above).

I am not submitting the refresh_token again (and that's an entirely separate process in my system as the refresh_token is not stored in the browser, and is sent to get a new token with ExpressJS)

I will continue to try and find out where the issue is, but after a while of trying I thought it was worth raising an issue here.

I did try putting in the logout on the firewall, but of course that's not going to do anything as stateless is true.

Any help or advice would be greatly appreciated.

security.yml

# To get started with security, check out the documentation:
# https://symfony.com/doc/current/security.html
security:
    encoders:
        Symfony\Component\Security\Core\User\User: plaintext
        FOS\UserBundle\Model\UserInterface:
            algorithm: bcrypt
            cost: 12

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: ROLE_ADMIN

    # https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
    providers:
        chain_provider:
            chain :
                providers: [in_memory, fos_userbundle]
        fos_userbundle:
            id: fos_user.user_provider.username
        in_memory:
            memory:
                users:
                    user:  { password: user, roles: [ 'ROLE_USER' ] }
                    admin: { password: admin, roles: [ 'ROLE_ADMIN' ] }

    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        login:
            pattern:  ^/login
            stateless: true
            anonymous: true
            form_login:
                check_path:               /login_check
                require_previous_session: false
                success_handler:          lexik_jwt_authentication.handler.authentication_success
                # We want failure to return back to the controller so we can reply with the same form in structure of other forms and display errors without additional code
                # failure_handler:        lexik_jwt_authentication.handler.authentication_failure

        api:
            pattern:   ^/
            stateless: true
            # These paths are accessed by users and admins - security added per controller/action
            anonymous: true
            logout:
                path: /logout
                invalidate_session: true
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator

    access_control:
        - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }

config.yml

imports:
    - { resource: parameters.yml }
    - { resource: phpcr.yml }
    - { resource: security.yml }
    - { resource: services.yml }
    - { resource: "@AppBundle/Resources/config/services.yml" }
    - { resource: "@DataBundle/Resources/config/services.yml" }
    - { resource: fos_rest.yml }

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
    locale: en

framework:
    #esi: ~
    translator: { fallbacks: ['%locale%'] }
    secret: '%secret%'
    router:
        resource: '%kernel.project_dir%/app/config/routing.yml'
        strict_requirements: ~
    form: ~
    csrf_protection: ~
    validation: { enable_annotations: true }
    #serializer: { enable_annotations: true }
    templating:
        engines: ['twig']
    default_locale: '%locale%'
    trusted_hosts: ~
    session:
        # https://symfony.com/doc/current/reference/configuration/framework.html#handler-id
        handler_id: session.handler.native_file
        save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
    fragments: ~
    http_method_override: true
    assets: ~
    php_errors:
        log: true

# Twig Configuration
twig:
    debug: '%kernel.debug%'
    strict_variables: '%kernel.debug%'
    form_themes:
        - '@App/Form/bulma_layout.html.twig'

# Doctrine Configuration
doctrine:
    dbal:
        driver: pdo_mysql
        host: '%database_host%'
        port: '%database_port%'
        dbname: '%database_name%'
        user: '%database_user%'
        password: '%database_password%'
        charset: utf8mb4
        default_table_options:
            charset: utf8mb4
            collate: utf8mb4_unicode_ci
        # if using pdo_sqlite as your database driver:
        #   1. add the path in parameters.yml
        #     e.g. database_path: "%kernel.project_dir%/var/data/data.sqlite"
        #   2. Uncomment database_path in parameters.yml.dist
        #   3. Uncomment next line:
        # path: '%database_path%'
    orm:
        auto_generate_proxy_classes: '%kernel.debug%'
        naming_strategy: doctrine.orm.naming_strategy.underscore
        auto_mapping: true

# Swiftmailer Configuration
swiftmailer:
    transport: '%mailer_transport%'
    host: '%mailer_host%'
    username: '%mailer_user%'
    password: '%mailer_password%'
    spool: { type: memory }

liip_imagine :
    resolvers :
        default :
            web_path : ~
    filter_sets :
        cache : ~
        220x220 :
            filters :
                thumbnail : { size : [220, 220], mode : outbound }
        tiny :
            filters :
                thumbnail : { size : [20, 20], mode : outbound }

# Nelmio Docs 3.X Beta 3
nelmio_api_doc:
    documentation:
        info:
            title: Starter Website API
            description: These are the API docs to communicate with the server-side of the Starter Website
            version: 0.0.1
        swagger:
            basePath: https://api.demo.starter.b-w.uk
    routes:
        path_patterns: # an array of regexps
            - ^\/(?!_)

# Nelmio CORS
nelmio_cors:
    paths:
        "^/":
            allow_credentials: true
            allow_origin:  ['http://127.0.0.1:8000', 'http://serve.b-w.uk', 'https://demo.starter.b-w.uk']
            allow_methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']
            allow_headers: ['content-type', 'access-control-request-method', 'access-control-request-headers', 'x-xsrf-token']
            max_age:       3600
            hosts:         ['^127.0.0.1']

#nelmio_security:
    #signed_cookie:
    #    names: ['PHPSESSID']
    #    secret: '%cookie_secret%'

endroid_twitter:
    consumer_key:           '%twitter.consumer_key%'
    consumer_secret:        '%twitter.consumer_secret%'
    access_token:           '%twitter.access_token%'
    access_token_secret:    '%twitter.access_token_secret%'

# cmf configuration
doctrine_phpcr:
    # configure the PHPCR session
    session:
        backend:   '%phpcr_backend%'
        workspace: '%phpcr_workspace%'
        username:  '%phpcr_user%'
        password:  '%phpcr_pass%'
    # enable the ODM layer
    odm:
        auto_mapping: true
        auto_generate_proxy_classes: '%kernel.debug%'
        locales:
            en: [de, fr]
            de: [en, fr]
            fr: [en, de]

doctrine_cache:
    providers:
        phpcr_meta:
            type: file_system
        phpcr_nodes:
            type: file_system

cmf_routing:
    chain:
        routers_by_id:
            cmf_routing.dynamic_router: 20
            router.default: 100
    dynamic:
        enabled: true
        persistence:
            phpcr: true
        controllers_by_class:
            DataBundle\Document\GenericPage: DataBundle\Controller\DefaultController::getPageAction
            DataBundle\Document\NewsPost: DataBundle\Controller\DefaultController::getPageAction
        route_collection_limit: 1

cmf_routing_auto:
    persistence:
        phpcr:
            enabled: true

jms_serializer:
    metadata:
        directories:
            DataBundle:
                namespace_prefix: "DataBundle"
                path: "@DataBundle/Resources/config/serializer"

cmf_seo:
    original_route_pattern: redirect

dunglas_angular_csrf:
    cookie:
        set_on:
            - { path: ^/, methods: [GET, HEAD] }
    secure:
        - { path: ^/, methods: [POST, PUT, PATCH, LINK, DELETE] }

lexik_jwt_authentication:
    private_key_path: '%jwt_private_key_path%'
    public_key_path:  '%jwt_public_key_path%'
    pass_phrase:      '%jwt_key_pass_phrase%'
    token_ttl:        '%jwt_token_ttl%'
    token_extractors:
        authorization_header:
            enabled: false
        cookie:
            enabled: true
            name:    TKN

gesdinet_jwt_refresh_token:
    ttl_update: true
    firewall: api
    user_provider: fos_user.user_provider.username_email
    ttl: 86400 # 1 day

fos_user:
    db_driver: orm
    firewall_name: api
    user_class: DataBundle\Entity\User
    from_email:
        address: "%mailer_user%"
        sender_name: "%mailer_user%"
silverbackdan commented 6 years ago

:see_no_evil: my mistake, login info still being sent from front-end - can't believe I missed it!