1

I have been working on setting up the FOSUserBundle/RestBundle/OAuthServerBundle trio to create a headless back end that I can then place a separate front end on top of, and eventually expand to mobile, and possible third party API access. I have the general configuration in place based on the various resources and instructions available and can generate an access token using client credentials.

The application this is being added to is an existing one that uses standard Symfony/Twig for front end/back end interaction and uses FOSUserBundle for authentication.

I have two problems related to the flow of authentication.

  1. I want the user to be able to access some parts of the API without authenticating past the client level, and some parts will require user-level authentication to verify they own the requested resources. I am not finding a way to do this. I've found posts talking about the possibility but nothing giving any direction on how it might be achieved. I believe I'll need to check at the controller level for appropriate access, maybe using custom voters, as checking for 'IS_AUTHENTICATED_FULLY' is coming back as true after just authenticating with the client. I want to be able to programmatically authenticate the user, bypassing the UI login form - that might just be overriding the FOSUserBundle login controller, but I'm not sure.
  2. I either need to create a client without an access token expiration or find a way to implement the refresh token. I don't really see why my own app should need to refresh a token, but if that is the standard way to do it I'm ok with following specs on that.

Below is some relevant code, though by and large the code is pretty box standard stuff copied over from the FOSOAuthServer setup guide.

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_email

    firewalls:
        oauth_token:
            pattern:    ^/oauth/v2/token
            security:   false

        rest:
            pattern: ^/rest(?!/doc)
            fos_oauth: true
            stateless: true
            anonymous: false

        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                csrf_token_generator: security.csrf.token_manager
                success_handler: security.authentication.success_handler
            use_referer: true
            logout:       true
            anonymous:    true

    access_control:
        - { path: ^/rest, roles: [ IS_AUTHENTICATED_FULLY ] }

config.yml snippet

fos_user:
    db_driver: orm
    firewall_name: main
    user_class: AppBundle\Entity\User
    registration:
        form:
            type: AppBundle\Form\Type\RegistrationFormType
    profile:
        form:
            type: user_profile

fos_oauth_server:
    db_driver: orm
    client_class:        AppBundle\Entity\Client
    access_token_class:  AppBundle\Entity\AccessToken
    refresh_token_class: AppBundle\Entity\RefreshToken
    auth_code_class:     AppBundle\Entity\AuthCode
    service:
        user_provider: fos_user.user_provider.username_email
        options:
            supported_scopes: user

fos_rest:
    view:
        view_response_listener: force
        formats:
            json: true
        templating_formats:
            html: true
        mime_types:
            json: ['application/json', 'application/json;version=1.0', 'application/json;version=1.1']
            jpg: ['image/jpeg']
            png: ['image/png']
    body_listener: true
    param_fetcher_listener: true
    allowed_methods_listener: true
    format_listener:
        rules:
            - { path: ^/, priorities: [html, json], fallback_format: json, prefer_extension: false }
TheGremlyn
  • 323
  • 1
  • 3
  • 21

1 Answers1

1

AD 1) I solved your problem with two firewalls in security.yml. Since Symfony is looking first match in security.yml I put first firewall to let anonymous users in:

api_anonym_area:
    pattern: (^/api/forgotten-password/.*)
    stateless:  true
    fos_oauth:  true
    anonymous: true

I catch URL with regex and give anonymous: true

As second firewall I have regex that catches all

api_auth_area:
    pattern:    ^/
    fos_oauth:  true
    stateless:  true
    anonymous:  false

So in your case, if you want anonymous users to get to /rest/doc, put in front of your firewall:rest something like this:

rest_doc:
    pattern: ^/rest/doc
    fos_oauth: true
    stateless: true
    anonymous: true

AD 2) Its not good practice to have unlimited access token lifetime, but you can do it in config.yml by setting big integer to access_token_lifetime:

fos_oauth_server:
    service:
        options:
            access_token_lifetime: #number in seconds#

To sign in with refresh token just

/oauth/v2/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

its in FOSOAuthServerBundle out of the box

  • after changing/adding access/refresh_token_lifetime, you need to run 'php app/console cache:clear --env=prod/dev' according yo your environment! – ani0904071 Jan 18 '21 at 08:10